Auto merge of #77015 - davidtwco:check-attr-variant-closure-expr, r=lcnr

passes: `check_attr` on more targets

This PR modifies `check_attr` so that:

- Enum variants are now checked (some attributes would not have been prohibited on variants previously).
- `check_expr_attributes` and `check_stmt_attributes` are removed as `check_attributes` can perform the same checks. This means that codegen attribute errors aren't shown if there are other errors first (e.g. from other attributes, as shown in `src/test/ui/macros/issue-68060.rs` changes below).
diff --git a/.github/ISSUE_TEMPLATE/regression.md b/.github/ISSUE_TEMPLATE/regression.md
new file mode 100644
index 0000000..ffab883
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/regression.md
@@ -0,0 +1,68 @@
+---
+name: Regression
+about: Report something that unexpectedly changed between Rust versions.
+labels: C-bug regression-untriaged
+---
+<!--
+Thank you for filing a regression report! 🐛 A regression is something that changed between versions of Rust but was not supposed to.
+
+Please provide a short summary of the regression, along with any information you feel is relevant to replicate it.
+-->
+
+### Code
+
+I tried this code:
+
+```rust
+<code>
+```
+
+I expected to see this happen: *explanation*
+
+Instead, this happened: *explanation*
+
+### Version it worked on
+
+<!--
+Provide the most recent version this worked on, for example:
+
+It most recently worked on: Rust 1.47
+-->
+
+It most recently worked on: <!-- version -->
+
+### Version with regression
+
+<!--
+Provide the version you are using that has the regression.
+-->
+
+`rustc --version --verbose`:
+```
+<version>
+```
+
+<!--
+Did the compiler crash? If so, please provide a backtrace.
+-->
+
+### Backtrace
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo build`.
+-->
+<details><summary>Backtrace</summary>
+<p>
+
+```
+<backtrace>
+```
+
+</p>
+</details>
+
+<!--
+If you know when this regression occurred, please add a line like below, replacing `{channel}` with one of stable, beta, or nightly.
+
+@rustbot modify labels: +regression-from-stable-to-{channel} -regression-untriaged
+-->
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 490258f..6025808 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -89,109 +89,8 @@
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
-      - name: install clang
-        run: src/ci/scripts/install-clang.sh
-        if: success() && !env.SKIP_JOB
-      - name: install WIX
-        run: src/ci/scripts/install-wix.sh
-        if: success() && !env.SKIP_JOB
-      - name: ensure the build happens on a partition with enough space
-        run: src/ci/scripts/symlink-build-dir.sh
-        if: success() && !env.SKIP_JOB
-      - name: disable git crlf conversion
-        run: src/ci/scripts/disable-git-crlf-conversion.sh
-        if: success() && !env.SKIP_JOB
-      - name: install MSYS2
-        run: src/ci/scripts/install-msys2.sh
-        if: success() && !env.SKIP_JOB
-      - name: install MinGW
-        run: src/ci/scripts/install-mingw.sh
-        if: success() && !env.SKIP_JOB
-      - name: install ninja
-        run: src/ci/scripts/install-ninja.sh
-        if: success() && !env.SKIP_JOB
-      - name: enable ipv6 on Docker
-        run: src/ci/scripts/enable-docker-ipv6.sh
-        if: success() && !env.SKIP_JOB
-      - name: disable git crlf conversion
-        run: src/ci/scripts/disable-git-crlf-conversion.sh
-        if: success() && !env.SKIP_JOB
-      - name: checkout submodules
-        run: src/ci/scripts/checkout-submodules.sh
-        if: success() && !env.SKIP_JOB
-      - name: ensure line endings are correct
-        run: src/ci/scripts/verify-line-endings.sh
-        if: success() && !env.SKIP_JOB
-      - name: run the build
-        run: src/ci/scripts/run-build-from-ci.sh
-        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 }}"
-        if: success() && !env.SKIP_JOB
-      - name: upload artifacts to S3
-        run: src/ci/scripts/upload-artifacts.sh
-        env:
-          AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
-          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
-        if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
-  try:
-    name: try
-    env:
-      CI_JOB_NAME: "${{ matrix.name }}"
-      SCCACHE_BUCKET: rust-lang-ci-sccache2
-      DEPLOY_BUCKET: rust-lang-ci2
-      TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
-      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
-      TOOLSTATE_PUBLISH: 1
-      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
-      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
-      CACHE_DOMAIN: ci-caches.rust-lang.org
-    if: "github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
-    strategy:
-      matrix:
-        include:
-          - name: dist-x86_64-linux
-            os: ubuntu-latest-xl
-            env: {}
-    timeout-minutes: 600
-    runs-on: "${{ matrix.os }}"
-    steps:
-      - name: disable git crlf conversion
-        run: git config --global core.autocrlf false
-      - name: checkout the source code
-        uses: actions/checkout@v1
-        with:
-          fetch-depth: 2
-      - name: configure the PR in which the error message will be posted
-        run: "echo \"[CI_PR_NUMBER=$num]\""
-        env:
-          num: "${{ github.event.number }}"
-        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
-      - name: add extra environment variables
-        run: src/ci/scripts/setup-environment.sh
-        env:
-          EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
-        if: success() && !env.SKIP_JOB
-      - name: decide whether to skip this job
-        run: src/ci/scripts/should-skip-this.sh
-        if: success() && !env.SKIP_JOB
-      - name: configure GitHub Actions to kill the build when outdated
-        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-        with:
-          github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
-      - name: collect CPU statistics
-        run: src/ci/scripts/collect-cpu-stats.sh
-        if: success() && !env.SKIP_JOB
-      - name: show the current environment
-        run: src/ci/scripts/dump-environment.sh
-        if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
-      - name: install sccache
-        run: src/ci/scripts/install-sccache.sh
+      - name: select Xcode
+        run: src/ci/scripts/select-xcode.sh
         if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
@@ -404,6 +303,20 @@
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
             os: macos-latest
+          - name: dist-aarch64-apple
+            env:
+              SCRIPT: "./x.py dist --stage 2"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              SELECT_XCODE: /Applications/Xcode_12.2.app
+              USE_XCODE_CLANG: 1
+              MACOSX_DEPLOYMENT_TARGET: 11.0
+              MACOSX_STD_DEPLOYMENT_TARGET: 11.0
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+              JEMALLOC_SYS_WITH_LG_PAGE: 14
+            os: macos-latest
           - name: x86_64-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -473,7 +386,7 @@
             os: windows-latest-xl
           - name: dist-x86_64-msvc
             env:
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
               SCRIPT: python x.py dist
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
@@ -483,6 +396,12 @@
               SCRIPT: python x.py dist
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
+          - name: dist-aarch64-msvc
+            env:
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
+              SCRIPT: python x.py dist
+              DIST_REQUIRE_ALL_TOOLS: 0
+            os: windows-latest-xl
           - name: dist-i686-mingw
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
@@ -541,6 +460,9 @@
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
+      - name: select Xcode
+        run: src/ci/scripts/select-xcode.sh
+        if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         if: success() && !env.SKIP_JOB
@@ -648,6 +570,116 @@
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
+      - name: select Xcode
+        run: src/ci/scripts/select-xcode.sh
+        if: success() && !env.SKIP_JOB
+      - name: install clang
+        run: src/ci/scripts/install-clang.sh
+        if: success() && !env.SKIP_JOB
+      - name: install WIX
+        run: src/ci/scripts/install-wix.sh
+        if: success() && !env.SKIP_JOB
+      - name: ensure the build happens on a partition with enough space
+        run: src/ci/scripts/symlink-build-dir.sh
+        if: success() && !env.SKIP_JOB
+      - name: disable git crlf conversion
+        run: src/ci/scripts/disable-git-crlf-conversion.sh
+        if: success() && !env.SKIP_JOB
+      - name: install MSYS2
+        run: src/ci/scripts/install-msys2.sh
+        if: success() && !env.SKIP_JOB
+      - name: install MinGW
+        run: src/ci/scripts/install-mingw.sh
+        if: success() && !env.SKIP_JOB
+      - name: install ninja
+        run: src/ci/scripts/install-ninja.sh
+        if: success() && !env.SKIP_JOB
+      - name: enable ipv6 on Docker
+        run: src/ci/scripts/enable-docker-ipv6.sh
+        if: success() && !env.SKIP_JOB
+      - name: disable git crlf conversion
+        run: src/ci/scripts/disable-git-crlf-conversion.sh
+        if: success() && !env.SKIP_JOB
+      - name: checkout submodules
+        run: src/ci/scripts/checkout-submodules.sh
+        if: success() && !env.SKIP_JOB
+      - name: ensure line endings are correct
+        run: src/ci/scripts/verify-line-endings.sh
+        if: success() && !env.SKIP_JOB
+      - name: run the build
+        run: src/ci/scripts/run-build-from-ci.sh
+        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 }}"
+        if: success() && !env.SKIP_JOB
+      - name: upload artifacts to S3
+        run: src/ci/scripts/upload-artifacts.sh
+        env:
+          AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
+          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
+        if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
+  try:
+    name: try
+    env:
+      CI_JOB_NAME: "${{ matrix.name }}"
+      SCCACHE_BUCKET: rust-lang-ci-sccache2
+      DEPLOY_BUCKET: rust-lang-ci2
+      TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
+      TOOLSTATE_PUBLISH: 1
+      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      CACHE_DOMAIN: ci-caches.rust-lang.org
+    if: "github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
+    strategy:
+      matrix:
+        include:
+          - name: dist-x86_64-linux
+            os: ubuntu-latest-xl
+            env: {}
+    timeout-minutes: 600
+    runs-on: "${{ matrix.os }}"
+    steps:
+      - name: disable git crlf conversion
+        run: git config --global core.autocrlf false
+      - name: checkout the source code
+        uses: actions/checkout@v1
+        with:
+          fetch-depth: 2
+      - name: configure the PR in which the error message will be posted
+        run: "echo \"[CI_PR_NUMBER=$num]\""
+        env:
+          num: "${{ github.event.number }}"
+        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
+      - name: add extra environment variables
+        run: src/ci/scripts/setup-environment.sh
+        env:
+          EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
+        if: success() && !env.SKIP_JOB
+      - name: decide whether to skip this job
+        run: src/ci/scripts/should-skip-this.sh
+        if: success() && !env.SKIP_JOB
+      - name: configure GitHub Actions to kill the build when outdated
+        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
+        with:
+          github_token: "${{ secrets.github_token }}"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+      - name: collect CPU statistics
+        run: src/ci/scripts/collect-cpu-stats.sh
+        if: success() && !env.SKIP_JOB
+      - name: show the current environment
+        run: src/ci/scripts/dump-environment.sh
+        if: success() && !env.SKIP_JOB
+      - name: install awscli
+        run: src/ci/scripts/install-awscli.sh
+        if: success() && !env.SKIP_JOB
+      - name: install sccache
+        run: src/ci/scripts/install-sccache.sh
+        if: success() && !env.SKIP_JOB
+      - name: select Xcode
+        run: src/ci/scripts/select-xcode.sh
+        if: success() && !env.SKIP_JOB
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         if: success() && !env.SKIP_JOB
diff --git a/.gitmodules b/.gitmodules
index d460b65..9841131 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -37,7 +37,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/11.0-2020-09-22
+	branch = rustc/11.0-2020-10-12
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
 	url = https://github.com/rust-embedded/book.git
diff --git a/.mailmap b/.mailmap
index fa0728b..f476926 100644
--- a/.mailmap
+++ b/.mailmap
@@ -29,7 +29,6 @@
 Austin Seipp <mad.one@gmail.com> <as@hacks.yi.org>
 Aydin Kim <ladinjin@hanmail.net> aydin.kim <aydin.kim@samsung.com>
 Barosl Lee <vcs@barosl.com> Barosl LEE <github@barosl.com>
-Bastian Kauschke <bastian_kauschke@hotmail.de>
 Ben Alpert <ben@benalpert.com> <spicyjalapeno@gmail.com>
 Ben Sago <ogham@users.noreply.github.com> Ben S <ogham@bsago.me>
 Ben Sago <ogham@users.noreply.github.com> Ben S <ogham@users.noreply.github.com>
@@ -161,6 +160,7 @@
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.com>
 Laurențiu Nicola <lnicola@dend.ro>
+lcnr <bastian_kauschke@hotmail.de>
 Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
 Lee Wondong <wdlee91@gmail.com>
 Lennart Kudling <github@kudling.de>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2a4c42e..b600074 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,14 +2,14 @@
 
 Thank you for your interest in contributing to Rust!
 
-To get started, read the [Getting Started] guide in the [rustc-dev-guide].
+To get started, read the [Contributing to Rust] chapter of the [rustc-dev-guide].
 
 ## Bug reports
 
 Did a compiler error message tell you to come here? If you want to create an ICE report,
 refer to [this section][contributing-bug-reports] and [open an issue][issue template].
 
-[Getting Started]: https://rustc-dev-guide.rust-lang.org/getting-started.html
+[Contributing to Rust]: https://rustc-dev-guide.rust-lang.org/contributing.html#contributing-to-rust
 [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
 [contributing-bug-reports]: https://rustc-dev-guide.rust-lang.org/contributing.html#bug-reports
 [issue template]: https://github.com/rust-lang/rust/issues/new/choose
diff --git a/Cargo.lock b/Cargo.lock
index d23b29d..94fbd52 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,13 +132,13 @@
 
 [[package]]
 name = "backtrace"
-version = "0.3.50"
+version = "0.3.53"
 dependencies = [
  "addr2line",
- "cfg-if",
+ "cfg-if 1.0.0",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.21.1",
  "rustc-demangle",
 ]
 
@@ -183,7 +183,16 @@
  "block-padding",
  "byte-tools",
  "byteorder",
- "generic-array",
+ "generic-array 0.12.3",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "generic-array 0.14.4",
 ]
 
 [[package]]
@@ -231,8 +240,15 @@
 name = "build-manifest"
 version = "0.1.0"
 dependencies = [
+ "anyhow",
+ "flate2",
+ "hex 0.4.2",
+ "num_cpus",
+ "rayon",
  "serde",
  "serde_json",
+ "sha2",
+ "tar",
  "toml",
 ]
 
@@ -279,7 +295,7 @@
 
 [[package]]
 name = "cargo"
-version = "0.49.0"
+version = "0.50.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -290,11 +306,11 @@
  "clap",
  "core-foundation",
  "crates-io",
- "crossbeam-utils 0.7.2",
+ "crossbeam-utils 0.8.0",
  "crypto-hash",
  "curl",
  "curl-sys",
- "env_logger 0.7.1",
+ "env_logger 0.8.1",
  "filetime",
  "flate2",
  "fwdansi",
@@ -426,10 +442,16 @@
 ]
 
 [[package]]
-name = "chalk-derive"
-version = "0.29.0"
+name = "cfg-if"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a7f257e3bcdc56d8877ae31c012bd69fba0be66929d588e603905f2632c0c59"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chalk-derive"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d072b2ba723f0bada7c515d8b3725224bc4f5052d2a92dcbeb0b118ff37084a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -439,9 +461,9 @@
 
 [[package]]
 name = "chalk-engine"
-version = "0.29.0"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c43fcc7edf4d51b42f44ed50e2337bd90ddc8e088d0cd78a71db92a6f780f782"
+checksum = "6fb5475f6083d6d6c509e1c335c4f69ad04144ac090faa1afb134a53c3695841"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -452,9 +474,9 @@
 
 [[package]]
 name = "chalk-ir"
-version = "0.29.0"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03a4050029ecb2b5a1ff3bfc64c39279179b294821ec2e8891a4a5c6e3a08db0"
+checksum = "f60cdb0e18c5455cb6a85e8464aad3622b70476018edfa8845691df66f7e9a05"
 dependencies = [
  "chalk-derive",
  "lazy_static",
@@ -462,9 +484,9 @@
 
 [[package]]
 name = "chalk-solve"
-version = "0.29.0"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "828c1f80d4eaf681027cce02050c54a3c97370f81988d31bf2a56df54048746c"
+checksum = "981534d499a8476ecc0b520be4d3864757f96211826a75360fbf2cb6fae362ab"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -533,7 +555,6 @@
  "cargo_metadata 0.11.1",
  "if_chain",
  "itertools 0.9.0",
- "lazy_static",
  "pulldown-cmark 0.8.0",
  "quine-mc_cluskey",
  "quote",
@@ -656,6 +677,12 @@
 ]
 
 [[package]]
+name = "const_fn"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2"
+
+[[package]]
 name = "constant_time_eq"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -685,6 +712,12 @@
 checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6"
 
 [[package]]
+name = "cpuid-bool"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
+
+[[package]]
 name = "crates-io"
 version = "0.31.1"
 dependencies = [
@@ -702,17 +735,17 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6"
+checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
 dependencies = [
- "cfg-if",
  "crossbeam-utils 0.7.2",
+ "maybe-uninit",
 ]
 
 [[package]]
@@ -733,7 +766,7 @@
 checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
 dependencies = [
  "autocfg",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "lazy_static",
  "maybe-uninit",
@@ -756,7 +789,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "maybe-uninit",
 ]
@@ -767,7 +800,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "lazy_static",
 ]
 
@@ -778,7 +811,19 @@
 checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
 dependencies = [
  "autocfg",
- "cfg-if",
+ "cfg-if 0.1.10",
+ "lazy_static",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5"
+dependencies = [
+ "autocfg",
+ "cfg-if 1.0.0",
+ "const_fn",
  "lazy_static",
 ]
 
@@ -881,7 +926,16 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
 dependencies = [
- "generic-array",
+ "generic-array 0.12.3",
+]
+
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array 0.14.4",
 ]
 
 [[package]]
@@ -899,7 +953,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "dirs-sys",
 ]
 
@@ -982,6 +1036,19 @@
 ]
 
 [[package]]
+name = "env_logger"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
+dependencies = [
+ "atty",
+ "humantime 2.0.1",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
 name = "error_index_generator"
 version = "0.0.0"
 dependencies = [
@@ -1041,7 +1108,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "redox_syscall",
  "winapi 0.3.9",
@@ -1059,7 +1126,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "crc32fast",
  "libc",
  "libz-sys",
@@ -1164,6 +1231,16 @@
 ]
 
 [[package]]
+name = "generic-array"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
 name = "getopts"
 version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1180,7 +1257,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "wasi",
 ]
@@ -1191,7 +1268,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "wasi",
 ]
@@ -1209,9 +1286,9 @@
 
 [[package]]
 name = "git2"
-version = "0.13.8"
+version = "0.13.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6ac22e49b7d886b6802c66662b12609452248b1bc9e87d6d83ecea3db96f557"
+checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224"
 dependencies = [
  "bitflags",
  "libc",
@@ -1620,18 +1697,18 @@
 
 [[package]]
 name = "libc"
-version = "0.2.77"
+version = "0.2.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
+checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "libgit2-sys"
-version = "0.12.9+1.0.1"
+version = "0.12.14+1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b33bf3d9d4c45b48ae1ea7c334be69994624dc0a69f833d5d9f7605f24b552b"
+checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549"
 dependencies = [
  "cc",
  "libc",
@@ -1653,9 +1730,9 @@
 
 [[package]]
 name = "libssh2-sys"
-version = "0.2.18"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eafa907407504b0e683786d4aba47acf250f114d37357d56608333fd167dd0fc"
+checksum = "ca46220853ba1c512fc82826d0834d87b06bcd3c2a42241b7de72f3d2fe17056"
 dependencies = [
  "cc",
  "libc",
@@ -1680,6 +1757,10 @@
 [[package]]
 name = "linkchecker"
 version = "0.1.0"
+dependencies = [
+ "once_cell",
+ "regex",
+]
 
 [[package]]
 name = "linked-hash-map"
@@ -1720,16 +1801,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
 dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "log_settings"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd"
-dependencies = [
- "lazy_static",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
@@ -1841,9 +1913,9 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8"
 dependencies = [
- "block-buffer",
- "digest",
- "opaque-debug",
+ "block-buffer 0.7.3",
+ "digest 0.8.1",
+ "opaque-debug 0.2.3",
 ]
 
 [[package]]
@@ -1959,7 +2031,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "fuchsia-zircon",
  "fuchsia-zircon-sys",
  "iovec",
@@ -2040,7 +2112,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "winapi 0.3.9",
 ]
@@ -2092,6 +2164,12 @@
 ]
 
 [[package]]
+name = "object"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693"
+
+[[package]]
 name = "once_cell"
 version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2104,6 +2182,12 @@
 checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
 
 [[package]]
+name = "opaque-debug"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+
+[[package]]
 name = "open"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2128,7 +2212,7 @@
 checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
 dependencies = [
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "foreign-types",
  "lazy_static",
  "libc",
@@ -2143,9 +2227,9 @@
 
 [[package]]
 name = "openssl-src"
-version = "111.10.2+1.1.1g"
+version = "111.12.0+1.1.1h"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a287fdb22e32b5b60624d4a5a7a02dbe82777f730ec0dbc42a0554326fef5a70"
+checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61"
 dependencies = [
  "cc",
 ]
@@ -2185,14 +2269,14 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
 name = "panic_abort"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
@@ -2203,7 +2287,7 @@
 version = "0.0.0"
 dependencies = [
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
@@ -2266,7 +2350,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "cloudabi 0.0.3",
  "libc",
  "redox_syscall",
@@ -2281,7 +2365,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "cloudabi 0.0.3",
  "libc",
  "redox_syscall",
@@ -2295,7 +2379,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "cloudabi 0.1.0",
  "instant",
  "libc",
@@ -2589,9 +2673,9 @@
 
 [[package]]
 name = "racer"
-version = "2.1.38"
+version = "2.1.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51dd5fd4247115b28f3e038eb8cda76a0c6f9cb473f769f41f930af8adff22d0"
+checksum = "b9424b4650b9c1134d0a1b34dab82319691e1c95fa8af1658fc640deb1b6823c"
 dependencies = [
  "bitflags",
  "clap",
@@ -2901,8 +2985,9 @@
 
 [[package]]
 name = "rust-demangler"
-version = "0.0.0"
+version = "0.0.1"
 dependencies = [
+ "regex",
  "rustc-demangle",
 ]
 
@@ -2916,9 +3001,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_arena"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2958af0d6e0458434a25cd3a96f6e19f24f71bf50b900add520dec52e212866b"
+checksum = "e8e941a8fc3878a111d2bbfe78e39522d884136f0b412b12592195f26f653476"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "smallvec 1.4.2",
@@ -2926,9 +3011,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_ast"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c82c2510460f2133548e62399e5acd30c25ae6ece30245baab3d1e00c2fefac"
+checksum = "3b58b6b035710df7f339a2bf86f6dafa876efd95439540970e24609e33598ca6"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -2943,11 +3028,11 @@
 
 [[package]]
 name = "rustc-ap-rustc_ast_passes"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83977da57f81c6edd89bad47e49136680eaa33288de4abb702e95358c2a0fc6c"
+checksum = "3d379a900d6a1f098490d92ab83e87487dcee2e4ec3f04c3ac4512b5117b64e2"
 dependencies = [
- "itertools 0.8.2",
+ "itertools 0.9.0",
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_ast_pretty",
  "rustc-ap-rustc_attr",
@@ -2962,9 +3047,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_ast_pretty"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "becf4ca1638b214694c71a8752192683048ab8bd47947cc481f57bd48157eeb9"
+checksum = "658d925c0da9e3c5cddc5e54f4fa8c03b41aff1fc6dc5e41837c1118ad010ac0"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_span",
@@ -2974,9 +3059,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_attr"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f21ca5dadce8a40d75a2756b77eab75b4c2d827f645c622dd93ee2285599640"
+checksum = "3f387037534f34c148aed753622677500e42d190a095670e7ac3fffc09811a59"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_ast_pretty",
@@ -2993,20 +3078,19 @@
 
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4cd204764727fde9abf75333eb661f058bfc7242062d91019440fe1b240688b"
+checksum = "14ffd17a37e00d77926a0713f191c59ff3aeb2b551a024c7cfffce14bab79be8"
 dependencies = [
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "ena",
  "indexmap",
  "jobserver",
- "lazy_static",
  "libc",
  "measureme",
- "parking_lot 0.10.2",
+ "parking_lot 0.11.0",
  "rustc-ap-rustc_graphviz",
  "rustc-ap-rustc_index",
  "rustc-ap-rustc_macros",
@@ -3024,9 +3108,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58116f119e37f14c029f99077b347069621118e048a69df74695b98204e7c136"
+checksum = "2b3263ddcfa9eb911e54a4e8088878dd9fd10e00d8b99b01033ba4a2733fe91d"
 dependencies = [
  "annotate-snippets 0.8.0",
  "atty",
@@ -3043,9 +3127,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_expand"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48e3c4bda9b64b92805bebe7431fdb8e24fd112b35a8c6d2174827441f10a6b2"
+checksum = "e1ab7e68cede8a2273fd8b8623002ce9dc832e061dfc3330e9bcc1fc2a722d73"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_ast_passes",
@@ -3066,32 +3150,31 @@
 
 [[package]]
 name = "rustc-ap-rustc_feature"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b612bb67d3fc49f395b03fc4ea4384a0145b05afbadab725803074ec827632b"
+checksum = "eea2dc95421bc19bbd4d939399833a882c46b684283b4267ad1fcf982fc043d9"
 dependencies = [
- "lazy_static",
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_span",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_fs_util"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7630ad1a73a8434ee920676148cb5440ac57509bd20e94ec41087fb0b1d11c28"
+checksum = "1e44c1804f09635f83f6cf1e04c2e92f8aeb7b4e850ac6c53d373dab02c13053"
 
 [[package]]
 name = "rustc-ap-rustc_graphviz"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a603fca4817062eb4fb23ff129d475bd66a69fb32f34ed4362ae950cf814b49d"
+checksum = "dc491f2b9be6e928f6df6b287549b8d50c48e8eff8638345155f40fa2cfb785d"
 
 [[package]]
 name = "rustc-ap-rustc_index"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9850c4a5d7c341513e10802bca9588bf8f452ceea2d5cfa87b934246a52622bc"
+checksum = "fa73f3fed413cdb6290738a10267da17b9ae8e02087334778b9a8c9491c5efc0"
 dependencies = [
  "arrayvec",
  "rustc-ap-rustc_macros",
@@ -3100,18 +3183,18 @@
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d86722e5a1a615b198327d0d794cd9cbc8b9db4542276fc51fe078924de68ea"
+checksum = "e993881244a92f3b44cf43c8f22ae2ca5cefe4f55a34e2b65b72ee66fe5ad077"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_macros"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3fc8482e44cabdda7ac9a8e224aef62ebdf95274d629dac8db3b42321025fea"
+checksum = "4effe366556e1d75344764adf4d54cba7c2fad33dbd07588e96d0853831ddc7c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3121,9 +3204,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_parse"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3716cdcd978a91dbd4a2788400e90e809527f841426fbeb92f882f9b8582f3ab"
+checksum = "0342675835251571471d3dca9ea1576a853a8dfa1f4b0084db283c861223cb60"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_ast",
@@ -3141,9 +3224,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_serialize"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c68046d07988b349b2e1c8bc1c9664a1d06519354aa677b9df358c5c5c058da0"
+checksum = "438255ed968d73bf6573aa18d3b8d33c0a85ecdfd14160ef09ff813938e0606c"
 dependencies = [
  "indexmap",
  "smallvec 1.4.2",
@@ -3151,9 +3234,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_session"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85735553501a4de0c8904e37b7ccef79cc1c585a7d7f2cfa02cc38e0d149f982"
+checksum = "7d61ff76dede8eb827f6805754900d1097a7046f938f950231b62b448f55bf78"
 dependencies = [
  "bitflags",
  "getopts",
@@ -3172,11 +3255,11 @@
 
 [[package]]
 name = "rustc-ap-rustc_span"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c49ae8a0d3b9e27c6ffe8febeaa30f899294fff012de70625f9ee81c54fda85"
+checksum = "1c267f15c3cfc82a8a441d2bf86bcccf299d1eb625822468e3d8ee6f7c5a1c89"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "md-5",
  "rustc-ap-rustc_arena",
  "rustc-ap-rustc_data_structures",
@@ -3191,9 +3274,9 @@
 
 [[package]]
 name = "rustc-ap-rustc_target"
-version = "677.0.0"
+version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1765f447594740c501c7b666b87639aa7c1dae2bf8c3166d5d2dca16646fd034"
+checksum = "8b1b4b266c4d44aac0f7f83b6741d8f0545b03d1ce32f3b5254f2014225cb96c"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3206,9 +3289,9 @@
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.16"
+version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
+checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -3302,7 +3385,6 @@
 name = "rustc_arena"
 version = "0.0.0"
 dependencies = [
- "rustc_data_structures",
  "smallvec 1.4.2",
 ]
 
@@ -3469,7 +3551,7 @@
 dependencies = [
  "arrayvec",
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "ena",
  "indexmap",
@@ -3520,6 +3602,7 @@
  "rustc_target",
  "tracing",
  "tracing-subscriber",
+ "tracing-tree",
  "winapi 0.3.9",
 ]
 
@@ -3807,7 +3890,6 @@
 dependencies = [
  "either",
  "itertools 0.9.0",
- "log_settings",
  "polonius-engine",
  "regex",
  "rustc_apfloat",
@@ -4020,7 +4102,7 @@
 name = "rustc_span"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "md-5",
  "rustc_arena",
  "rustc_data_structures",
@@ -4210,7 +4292,7 @@
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.21"
+version = "1.4.22"
 dependencies = [
  "annotate-snippets 0.6.1",
  "anyhow",
@@ -4368,10 +4450,23 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
 dependencies = [
- "block-buffer",
- "digest",
+ "block-buffer 0.7.3",
+ "digest 0.8.1",
  "fake-simd",
- "opaque-debug",
+ "opaque-debug 0.2.3",
+]
+
+[[package]]
+name = "sha2"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if 0.1.10",
+ "cpuid-bool",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
 ]
 
 [[package]]
@@ -4454,7 +4549,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "redox_syscall",
  "winapi 0.3.9",
@@ -4473,7 +4568,7 @@
 checksum = "21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786"
 dependencies = [
  "cc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "psm",
  "winapi 0.3.9",
@@ -4485,7 +4580,7 @@
 dependencies = [
  "addr2line",
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "dlmalloc",
@@ -4494,7 +4589,7 @@
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.20.0",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -4627,7 +4722,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "rand",
  "redox_syscall",
@@ -4687,7 +4782,7 @@
 name = "test"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "core",
  "getopts",
  "libc",
@@ -5019,9 +5114,9 @@
 
 [[package]]
 name = "toml"
-version = "0.5.6"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
+checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"
 dependencies = [
  "serde",
 ]
@@ -5032,7 +5127,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "tracing-attributes",
  "tracing-core",
 ]
@@ -5050,9 +5145,9 @@
 
 [[package]]
 name = "tracing-core"
-version = "0.1.15"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5"
+checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
 dependencies = [
  "lazy_static",
 ]
@@ -5070,9 +5165,9 @@
 
 [[package]]
 name = "tracing-serde"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6ccba2f8f16e0ed268fc765d9b7ff22e965e7185d32f8f1ec8294fe17d86e79"
+checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
 dependencies = [
  "serde",
  "tracing-core",
@@ -5080,9 +5175,9 @@
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.2.11"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abd165311cc4d7a555ad11cc77a37756df836182db0d81aac908c8184c584f40"
+checksum = "4ef0a5e15477aa303afbfac3a44cba9b6430fdaad52423b1e6c0dbbe28c3eedd"
 dependencies = [
  "ansi_term 0.12.1",
  "chrono",
@@ -5095,6 +5190,7 @@
  "sharded-slab",
  "smallvec 1.4.2",
  "thread_local",
+ "tracing",
  "tracing-core",
  "tracing-log",
  "tracing-serde",
@@ -5102,9 +5198,9 @@
 
 [[package]]
 name = "tracing-tree"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1a3dc4774db3a6b2d66a4f8d8de670e874ec3ed55615860c994927419b32c5f"
+checksum = "43aac8afb493b08e1e1904956f7407c1e671b9c83b26a17e1bd83d6a3520e350"
 dependencies = [
  "ansi_term 0.12.1",
  "atty",
@@ -5228,7 +5324,7 @@
 version = "0.0.0"
 dependencies = [
  "cc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
diff --git a/README.md b/README.md
index d445bbd..07c0960 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,7 @@
 
 **Note: this README is for _users_ rather than _contributors_.
 If you wish to _contribute_ to the compiler, you should read the
-[Getting Started][gettingstarted] of the rustc-dev-guide instead of this
-section.**
+[Getting Started][gettingstarted] section of the rustc-dev-guide instead.**
 
 ## Quick Start
 
diff --git a/RELEASES.md b/RELEASES.md
index 0f59d72..ce11a74 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,138 @@
+Version 1.47.0 (2020-10-08)
+==========================
+
+Language
+--------
+- [Closures will now warn when not used.][74869]
+
+Compiler
+--------
+- [Stabilized the `-C control-flow-guard` codegen option][73893], which enables
+  [Control Flow Guard][1.47.0-cfg] for Windows platforms, and is ignored on other
+  platforms.
+- [Upgraded to LLVM 11.][73526]
+- [Added tier 3\* support for the `thumbv4t-none-eabi` target.][74419]
+- [Upgrade the FreeBSD toolchain to version 11.4][75204]
+- [`RUST_BACKTRACE`'s output is now more compact.][75048]
+
+\* Refer to Rust's [platform support page][forge-platform-support] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+- [`CStr` now implements `Index<RangeFrom<usize>>`.][74021]
+- [Traits in `std`/`core` are now implemented for arrays of any length, not just
+  those of length less than 33.][74060]
+- [`ops::RangeFull` and `ops::Range` now implement Default.][73197]
+- [`panic::Location` now implements `Copy`, `Clone`, `Eq`, `Hash`, `Ord`,
+  `PartialEq`, and `PartialOrd`.][73583]
+
+Stabilized APIs
+---------------
+- [`Ident::new_raw`]
+- [`Range::is_empty`]
+- [`RangeInclusive::is_empty`]
+- [`Result::as_deref`]
+- [`Result::as_deref_mut`]
+- [`Vec::leak`]
+- [`pointer::offset_from`]
+- [`f32::TAU`]
+- [`f64::TAU`]
+
+The following previously stable APIs have now been made const.
+
+- [The `new` method for all `NonZero` integers.][73858]
+- [The `checked_add`,`checked_sub`,`checked_mul`,`checked_neg`, `checked_shl`,
+  `checked_shr`, `saturating_add`, `saturating_sub`, and `saturating_mul`
+  methods for all integers.][73858]
+- [The `checked_abs`, `saturating_abs`, `saturating_neg`, and `signum`  for all
+  signed integers.][73858]
+- [The `is_ascii_alphabetic`, `is_ascii_uppercase`, `is_ascii_lowercase`,
+  `is_ascii_alphanumeric`, `is_ascii_digit`, `is_ascii_hexdigit`,
+  `is_ascii_punctuation`, `is_ascii_graphic`, `is_ascii_whitespace`, and
+  `is_ascii_control` methods for `char` and `u8`.][73858]
+
+Cargo
+-----
+- [`build-dependencies` are now built with opt-level 0 by default.][cargo/8500]
+  You can override this by setting the following in your `Cargo.toml`.
+  ```toml
+  [profile.release.build-override]
+  opt-level = 3
+  ```
+- [`cargo-help` will now display man pages for commands rather just the
+  `--help` text.][cargo/8456]
+- [`cargo-metadata` now emits a `test` field indicating if a target has
+  tests enabled.][cargo/8478]
+- [`workspace.default-members` now respects `workspace.exclude`.][cargo/8485]
+- [`cargo-publish` will now use an alternative registry by default if it's the
+  only registry specified in `package.publish`.][cargo/8571]
+
+Misc
+----
+- [Added a help button beside Rustdoc's searchbar that explains rustdoc's
+  type based search.][75366]
+- [Added the Ayu theme to rustdoc.][71237]
+
+Compatibility Notes
+-------------------
+- [Bumped the minimum supported Emscripten version to 1.39.20.][75716]
+- [Fixed a regression parsing `{} && false` in tail expressions.][74650]
+- [Added changes to how proc-macros are expanded in `macro_rules!` that should
+  help to preserve more span information.][73084] These changes may cause
+  compiliation errors if your macro was unhygenic or didn't correctly handle
+  `Delimiter::None`.
+- [Moved support for the CloudABI target to tier 3.][75568]
+- [`linux-gnu` targets now require minimum kernel 2.6.32 and glibc 2.11.][74163]
+- [Added the `rustc-docs` component.][75560] This allows you to install
+  and read the documentation for the compiler internal APIs. (Currently only
+  available for `x86_64-unknown-linux-gnu`.)
+
+Internal Only
+--------
+- [Improved default settings for bootstrapping in `x.py`.][73964] You can read details about this change in the ["Changes to `x.py` defaults"](https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html) post on the Inside Rust blog.
+
+[1.47.0-cfg]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
+[75048]: https://github.com/rust-lang/rust/pull/75048/
+[74163]: https://github.com/rust-lang/rust/pull/74163/
+[71237]: https://github.com/rust-lang/rust/pull/71237/
+[74869]: https://github.com/rust-lang/rust/pull/74869/
+[73858]: https://github.com/rust-lang/rust/pull/73858/
+[75716]: https://github.com/rust-lang/rust/pull/75716/
+[75908]: https://github.com/rust-lang/rust/pull/75908/
+[75516]: https://github.com/rust-lang/rust/pull/75516/
+[75560]: https://github.com/rust-lang/rust/pull/75560/
+[75568]: https://github.com/rust-lang/rust/pull/75568/
+[75366]: https://github.com/rust-lang/rust/pull/75366/
+[75204]: https://github.com/rust-lang/rust/pull/75204/
+[74650]: https://github.com/rust-lang/rust/pull/74650/
+[74419]: https://github.com/rust-lang/rust/pull/74419/
+[73964]: https://github.com/rust-lang/rust/pull/73964/
+[74021]: https://github.com/rust-lang/rust/pull/74021/
+[74060]: https://github.com/rust-lang/rust/pull/74060/
+[73893]: https://github.com/rust-lang/rust/pull/73893/
+[73526]: https://github.com/rust-lang/rust/pull/73526/
+[73583]: https://github.com/rust-lang/rust/pull/73583/
+[73084]: https://github.com/rust-lang/rust/pull/73084/
+[73197]: https://github.com/rust-lang/rust/pull/73197/
+[72488]: https://github.com/rust-lang/rust/pull/72488/
+[cargo/8456]: https://github.com/rust-lang/cargo/pull/8456/
+[cargo/8478]: https://github.com/rust-lang/cargo/pull/8478/
+[cargo/8485]: https://github.com/rust-lang/cargo/pull/8485/
+[cargo/8500]: https://github.com/rust-lang/cargo/pull/8500/
+[cargo/8571]: https://github.com/rust-lang/cargo/pull/8571/
+[`Ident::new_raw`]:  https://doc.rust-lang.org/nightly/proc_macro/struct.Ident.html#method.new_raw
+[`Range::is_empty`]: https://doc.rust-lang.org/nightly/std/ops/struct.Range.html#method.is_empty
+[`RangeInclusive::is_empty`]: https://doc.rust-lang.org/nightly/std/ops/struct.RangeInclusive.html#method.is_empty
+[`Result::as_deref_mut`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#method.as_deref_mut
+[`Result::as_deref`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#method.as_deref
+[`TypeId::of`]: https://doc.rust-lang.org/nightly/std/any/struct.TypeId.html#method.of
+[`Vec::leak`]: https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.leak
+[`f32::TAU`]: https://doc.rust-lang.org/nightly/std/f32/consts/constant.TAU.html
+[`f64::TAU`]: https://doc.rust-lang.org/nightly/std/f64/consts/constant.TAU.html
+[`pointer::offset_from`]: https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.offset_from
+
+
 Version 1.46.0 (2020-08-27)
 ==========================
 
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs
index e3d941c..71bcb8f 100644
--- a/compiler/rustc_apfloat/src/ieee.rs
+++ b/compiler/rustc_apfloat/src/ieee.rs
@@ -1511,11 +1511,16 @@
                 sig::set_bit(&mut r.sig, T::PRECISION - 1);
             }
 
-            // gcc forces the Quiet bit on, which means (float)(double)(float_sNan)
-            // does not give you back the same bits. This is dubious, and we
-            // don't currently do it. You're really supposed to get
-            // an invalid operation signal at runtime, but nobody does that.
-            status = Status::OK;
+            // Convert of sNaN creates qNaN and raises an exception (invalid op).
+            // This also guarantees that a sNaN does not become Inf on a truncation
+            // that loses all payload bits.
+            if self.is_signaling() {
+                // Quiet signaling NaN.
+                sig::set_bit(&mut r.sig, T::QNAN_BIT);
+                status = Status::INVALID_OP;
+            } else {
+                status = Status::OK;
+            }
         } else {
             *loses_info = false;
             status = Status::OK;
diff --git a/compiler/rustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs
index 2d8bb7d..63d925c 100644
--- a/compiler/rustc_apfloat/tests/ieee.rs
+++ b/compiler/rustc_apfloat/tests/ieee.rs
@@ -567,6 +567,17 @@
 }
 
 #[test]
+fn issue_69532() {
+    let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128);
+    let mut loses_info = false;
+    let sta = f.convert(&mut loses_info);
+    let r: Single = sta.value;
+    assert!(loses_info);
+    assert!(r.is_nan());
+    assert_eq!(sta.status, Status::INVALID_OP);
+}
+
+#[test]
 fn min_num() {
     let f1 = Double::from_f64(1.0);
     let f2 = Double::from_f64(2.0);
@@ -1492,27 +1503,32 @@
     assert_eq!(4294967295.0, test.to_f64());
     assert!(!loses_info);
 
-    let test = Single::snan(None);
-    let x87_snan = X87DoubleExtended::snan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_snan));
-    assert!(!loses_info);
-
     let test = Single::qnan(None);
     let x87_qnan = X87DoubleExtended::qnan(None);
     let test: X87DoubleExtended = test.convert(&mut loses_info).value;
     assert!(test.bitwise_eq(x87_qnan));
     assert!(!loses_info);
 
-    let test = X87DoubleExtended::snan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_snan));
+    let test = Single::snan(None);
+    let sta = test.convert(&mut loses_info);
+    let test: X87DoubleExtended = sta.value;
+    assert!(test.is_nan());
+    assert!(!test.is_signaling());
     assert!(!loses_info);
+    assert_eq!(sta.status, Status::INVALID_OP);
 
     let test = X87DoubleExtended::qnan(None);
     let test: X87DoubleExtended = test.convert(&mut loses_info).value;
     assert!(test.bitwise_eq(x87_qnan));
     assert!(!loses_info);
+
+    let test = X87DoubleExtended::snan(None);
+    let sta = test.convert(&mut loses_info);
+    let test: X87DoubleExtended = sta.value;
+    assert!(test.is_nan());
+    assert!(!test.is_signaling());
+    assert!(!loses_info);
+    assert_eq!(sta.status, Status::INVALID_OP);
 }
 
 #[test]
diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml
index 41701f3..29caa85 100644
--- a/compiler/rustc_arena/Cargo.toml
+++ b/compiler/rustc_arena/Cargo.toml
@@ -5,5 +5,4 @@
 edition = "2018"
 
 [dependencies]
-rustc_data_structures = { path = "../rustc_data_structures" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 166f7f5..1a85a46 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -16,7 +16,6 @@
 #![feature(maybe_uninit_slice)]
 #![cfg_attr(test, feature(test))]
 
-use rustc_data_structures::cold_path;
 use smallvec::SmallVec;
 
 use std::alloc::Layout;
@@ -27,6 +26,12 @@
 use std::ptr;
 use std::slice;
 
+#[inline(never)]
+#[cold]
+pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
+    f()
+}
+
 /// An arena that can hold objects of only one type.
 pub struct TypedArena<T> {
     /// A pointer to the next object to be allocated.
@@ -212,16 +217,18 @@
             let mut chunks = self.chunks.borrow_mut();
             let mut new_cap;
             if let Some(last_chunk) = chunks.last_mut() {
-                let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
-                last_chunk.entries = used_bytes / mem::size_of::<T>();
+                // If a type is `!needs_drop`, we don't need to keep track of how many elements
+                // the chunk stores - the field will be ignored anyway.
+                if mem::needs_drop::<T>() {
+                    let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
+                    last_chunk.entries = used_bytes / mem::size_of::<T>();
+                }
 
                 // If the previous chunk's len is less than HUGE_PAGE
                 // bytes, then this chunk will be least double the previous
                 // chunk's size.
-                new_cap = last_chunk.storage.len();
-                if new_cap < HUGE_PAGE / elem_size {
-                    new_cap = new_cap.checked_mul(2).unwrap();
-                }
+                new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2);
+                new_cap = new_cap * 2;
             } else {
                 new_cap = PAGE / elem_size;
             }
@@ -338,10 +345,8 @@
                 // If the previous chunk's len is less than HUGE_PAGE
                 // bytes, then this chunk will be least double the previous
                 // chunk's size.
-                new_cap = last_chunk.storage.len();
-                if new_cap < HUGE_PAGE {
-                    new_cap = new_cap.checked_mul(2).unwrap();
-                }
+                new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2);
+                new_cap = new_cap * 2;
             } else {
                 new_cap = PAGE;
             }
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 95abf55..9eb934c 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -24,9 +24,10 @@
 
 use crate::ptr::P;
 use crate::token::{self, CommentKind, DelimToken};
-use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_macros::HashStable_Generic;
@@ -96,7 +97,7 @@
     /// The segments in the path: the things separated by `::`.
     /// Global paths begin with `kw::PathRoot`.
     pub segments: Vec<PathSegment>,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 impl PartialEq<Symbol> for Path {
@@ -166,13 +167,6 @@
 }
 
 impl GenericArgs {
-    pub fn is_parenthesized(&self) -> bool {
-        match *self {
-            Parenthesized(..) => true,
-            _ => false,
-        }
-    }
-
     pub fn is_angle_bracketed(&self) -> bool {
         match *self {
             AngleBracketed(..) => true,
@@ -541,7 +535,7 @@
     /// Distinguishes between `unsafe { ... }` and `{ ... }`.
     pub rules: BlockCheckMode,
     pub span: Span,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 /// A match pattern.
@@ -552,7 +546,7 @@
     pub id: NodeId,
     pub kind: PatKind,
     pub span: Span,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 impl Pat {
@@ -856,13 +850,6 @@
         }
     }
 
-    pub fn is_shift(&self) -> bool {
-        match *self {
-            BinOpKind::Shl | BinOpKind::Shr => true,
-            _ => false,
-        }
-    }
-
     pub fn is_comparison(&self) -> bool {
         use BinOpKind::*;
         // Note for developers: please keep this as is;
@@ -872,11 +859,6 @@
             And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false,
         }
     }
-
-    /// Returns `true` if the binary operator takes its arguments by value
-    pub fn is_by_value(&self) -> bool {
-        !self.is_comparison()
-    }
 }
 
 pub type BinOp = Spanned<BinOpKind>;
@@ -895,14 +877,6 @@
 }
 
 impl UnOp {
-    /// Returns `true` if the unary operator takes its argument by value
-    pub fn is_by_value(u: UnOp) -> bool {
-        match u {
-            UnOp::Neg | UnOp::Not => true,
-            _ => false,
-        }
-    }
-
     pub fn to_string(op: UnOp) -> &'static str {
         match op {
             UnOp::Deref => "*",
@@ -918,7 +892,7 @@
     pub id: NodeId,
     pub kind: StmtKind,
     pub span: Span,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 impl Stmt {
@@ -1066,7 +1040,7 @@
     pub kind: ExprKind,
     pub span: Span,
     pub attrs: AttrVec,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -1178,6 +1152,7 @@
         match self.kind {
             ExprKind::Box(_) => ExprPrecedence::Box,
             ExprKind::Array(_) => ExprPrecedence::Array,
+            ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
             ExprKind::Call(..) => ExprPrecedence::Call,
             ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
             ExprKind::Tup(_) => ExprPrecedence::Tup,
@@ -1233,6 +1208,8 @@
     Box(P<Expr>),
     /// An array (`[a, b, c, d]`)
     Array(Vec<P<Expr>>),
+    /// Allow anonymous constants from an inline `const` block
+    ConstBlock(AnonConst),
     /// A function call
     ///
     /// The first field resolves to the function itself,
@@ -1606,7 +1583,7 @@
     /// A string literal (`"foo"`).
     Str(Symbol, StrStyle),
     /// A byte string (`b"foo"`).
-    ByteStr(Lrc<Vec<u8>>),
+    ByteStr(Lrc<[u8]>),
     /// A byte char (`b'f'`).
     Byte(u8),
     /// A character literal (`'a'`).
@@ -1752,13 +1729,6 @@
         }
     }
 
-    pub fn val_to_string(&self, val: i128) -> String {
-        // Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types
-        // are parsed as `u128`, so we wouldn't want to print an extra negative
-        // sign.
-        format!("{}{}", val as u128, self.name_str())
-    }
-
     pub fn bit_width(&self) -> Option<u64> {
         Some(match *self {
             IntTy::Isize => return None,
@@ -1817,10 +1787,6 @@
         }
     }
 
-    pub fn val_to_string(&self, val: u128) -> String {
-        format!("{}{}", val, self.name_str())
-    }
-
     pub fn bit_width(&self) -> Option<u64> {
         Some(match *self {
             UintTy::Usize => return None,
@@ -1864,12 +1830,33 @@
     Bound { bounds: GenericBounds },
 }
 
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Encodable, Decodable, Debug)]
 pub struct Ty {
     pub id: NodeId,
     pub kind: TyKind,
     pub span: Span,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
+}
+
+impl Clone for Ty {
+    fn clone(&self) -> Self {
+        ensure_sufficient_stack(|| Self {
+            id: self.id,
+            kind: self.kind.clone(),
+            span: self.span,
+            tokens: self.tokens.clone(),
+        })
+    }
+}
+
+impl Ty {
+    pub fn peel_refs(&self) -> &Self {
+        let mut final_ty = self;
+        while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+            final_ty = &ty;
+        }
+        final_ty
+    }
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -2421,7 +2408,7 @@
 pub struct AttrItem {
     pub path: Path,
     pub args: MacArgs,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 /// A list of attributes.
@@ -2495,7 +2482,7 @@
 pub struct Visibility {
     pub kind: VisibilityKind,
     pub span: Span,
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -2582,7 +2569,7 @@
     ///
     /// Note that the tokens here do not include the outer attributes, but will
     /// include inner attributes.
-    pub tokens: Option<TokenStream>,
+    pub tokens: Option<LazyTokenStream>,
 }
 
 impl Item {
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 2782869..8351be2 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -101,11 +101,6 @@
         self.meta_item().is_some()
     }
 
-    /// Returns `true` if the variant is `Literal`.
-    pub fn is_literal(&self) -> bool {
-        self.literal().is_some()
-    }
-
     /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
     pub fn is_word(&self) -> bool {
         self.meta_item().map_or(false, |meta_item| meta_item.is_word())
@@ -232,10 +227,6 @@
     pub fn is_value_str(&self) -> bool {
         self.value_str().is_some()
     }
-
-    pub fn is_meta_item_list(&self) -> bool {
-        self.meta_item_list().is_some()
-    }
 }
 
 impl AttrItem {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 425ef83..382003c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1106,6 +1106,9 @@
     match kind {
         ExprKind::Box(expr) => vis.visit_expr(expr),
         ExprKind::Array(exprs) => visit_exprs(exprs, vis),
+        ExprKind::ConstBlock(anon_const) => {
+            vis.visit_anon_const(anon_const);
+        }
         ExprKind::Repeat(expr, count) => {
             vis.visit_expr(expr);
             vis.visit_anon_const(count);
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index d5b3e87..d991027 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -54,16 +54,6 @@
     NoDelim,
 }
 
-impl DelimToken {
-    pub fn len(self) -> usize {
-        if self == NoDelim { 0 } else { 1 }
-    }
-
-    pub fn is_empty(self) -> bool {
-        self == NoDelim
-    }
-}
-
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum LitKind {
     Bool, // AST only, must never appear in a `Token`
@@ -163,6 +153,7 @@
             kw::Do,
             kw::Box,
             kw::Break,
+            kw::Const,
             kw::Continue,
             kw::False,
             kw::For,
@@ -810,10 +801,10 @@
             if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
                 let filename = source_map.span_to_filename(orig_span);
                 if let FileName::Real(RealFileName::Named(path)) = filename {
-                    let matches_prefix = |prefix| {
-                        // Check for a path that ends with 'prefix*/src/lib.rs'
+                    let matches_prefix = |prefix, filename| {
+                        // Check for a path that ends with 'prefix*/src/<filename>'
                         let mut iter = path.components().rev();
-                        iter.next().and_then(|p| p.as_os_str().to_str()) == Some("lib.rs")
+                        iter.next().and_then(|p| p.as_os_str().to_str()) == Some(filename)
                             && iter.next().and_then(|p| p.as_os_str().to_str()) == Some("src")
                             && iter
                                 .next()
@@ -821,14 +812,25 @@
                                 .map_or(false, |p| p.starts_with(prefix))
                     };
 
-                    if (macro_name == sym::impl_macros && matches_prefix("time-macros-impl"))
-                        || (macro_name == sym::arrays && matches_prefix("js-sys"))
+                    if (macro_name == sym::impl_macros
+                        && matches_prefix("time-macros-impl", "lib.rs"))
+                        || (macro_name == sym::arrays && matches_prefix("js-sys", "lib.rs"))
                     {
                         let snippet = source_map.span_to_snippet(orig_span);
                         if snippet.as_deref() == Ok("$name") {
                             return Some((*ident, *is_raw));
                         }
                     }
+
+                    if macro_name == sym::tuple_from_req
+                        && (matches_prefix("actix-web", "extract.rs")
+                            || matches_prefix("actori-web", "extract.rs"))
+                    {
+                        let snippet = source_map.span_to_snippet(orig_span);
+                        if snippet.as_deref() == Ok("$T") {
+                            return Some((*ident, *is_raw));
+                        }
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index f201f0b..cb419b6 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -16,8 +16,9 @@
 use crate::token::{self, DelimToken, Token, TokenKind};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
 use rustc_macros::HashStable_Generic;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
@@ -119,13 +120,84 @@
     }
 }
 
+// A cloneable callback which produces a `TokenStream`. Each clone
+// of this should produce the same `TokenStream`
+pub trait CreateTokenStream: sync::Send + sync::Sync + FnOnce() -> TokenStream {
+    // Workaround for the fact that `Clone` is not object-safe
+    fn clone_it(&self) -> Box<dyn CreateTokenStream>;
+}
+
+impl<F: 'static + Clone + sync::Send + sync::Sync + FnOnce() -> TokenStream> CreateTokenStream
+    for F
+{
+    fn clone_it(&self) -> Box<dyn CreateTokenStream> {
+        Box::new(self.clone())
+    }
+}
+
+impl Clone for Box<dyn CreateTokenStream> {
+    fn clone(&self) -> Self {
+        let val: &(dyn CreateTokenStream) = &**self;
+        val.clone_it()
+    }
+}
+
+/// A lazy version of `TokenStream`, which may defer creation
+/// of an actual `TokenStream` until it is needed.
+pub type LazyTokenStream = Lrc<LazyTokenStreamInner>;
+
+#[derive(Clone)]
+pub enum LazyTokenStreamInner {
+    Lazy(Box<dyn CreateTokenStream>),
+    Ready(TokenStream),
+}
+
+impl std::fmt::Debug for LazyTokenStreamInner {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            LazyTokenStreamInner::Lazy(..) => f.debug_struct("LazyTokenStream::Lazy").finish(),
+            LazyTokenStreamInner::Ready(..) => f.debug_struct("LazyTokenStream::Ready").finish(),
+        }
+    }
+}
+
+impl LazyTokenStreamInner {
+    pub fn into_token_stream(&self) -> TokenStream {
+        match self {
+            // Note that we do not cache this. If this ever becomes a performance
+            // problem, we should investigate wrapping `LazyTokenStreamInner`
+            // in a lock
+            LazyTokenStreamInner::Lazy(cb) => (cb.clone())(),
+            LazyTokenStreamInner::Ready(stream) => stream.clone(),
+        }
+    }
+}
+
+impl<S: Encoder> Encodable<S> for LazyTokenStreamInner {
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        panic!("Attempted to encode LazyTokenStream");
+    }
+}
+
+impl<D: Decoder> Decodable<D> for LazyTokenStreamInner {
+    fn decode(_d: &mut D) -> Result<Self, D::Error> {
+        panic!("Attempted to decode LazyTokenStream");
+    }
+}
+
+impl<CTX> HashStable<CTX> for LazyTokenStreamInner {
+    fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
+        panic!("Attempted to compute stable hash for LazyTokenStream");
+    }
+}
+
 /// A `TokenStream` is an abstract sequence of tokens, organized into `TokenTree`s.
 ///
 /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
 /// instead of a representation of the abstract syntax tree.
 /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat.
 #[derive(Clone, Debug, Default, Encodable, Decodable)]
-pub struct TokenStream(pub Lrc<Vec<TreeAndSpacing>>);
+pub struct TokenStream(pub(crate) Lrc<Vec<TreeAndSpacing>>);
 
 pub type TreeAndSpacing = (TokenTree, Spacing);
 
@@ -286,21 +358,15 @@
         t1.next().is_none() && t2.next().is_none()
     }
 
-    pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
+    pub fn map_enumerated<F: FnMut(usize, &TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
         TokenStream(Lrc::new(
             self.0
                 .iter()
                 .enumerate()
-                .map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
+                .map(|(i, (tree, is_joint))| (f(i, tree), *is_joint))
                 .collect(),
         ))
     }
-
-    pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
-        TokenStream(Lrc::new(
-            self.0.iter().map(|(tree, is_joint)| (f(tree.clone()), *is_joint)).collect(),
-        ))
-    }
 }
 
 // 99.5%+ of the time we have 1 or 2 elements in this vector.
@@ -400,8 +466,8 @@
         self.index = index;
     }
 
-    pub fn look_ahead(&self, n: usize) -> Option<TokenTree> {
-        self.stream.0[self.index..].get(n).map(|(tree, _)| tree.clone())
+    pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
+        self.stream.0[self.index..].get(n).map(|(tree, _)| tree)
     }
 }
 
diff --git a/compiler/rustc_ast/src/util/lev_distance.rs b/compiler/rustc_ast/src/util/lev_distance.rs
index 754b1f1..21c2c92 100644
--- a/compiler/rustc_ast/src/util/lev_distance.rs
+++ b/compiler/rustc_ast/src/util/lev_distance.rs
@@ -54,7 +54,7 @@
     T: Iterator<Item = &'a Symbol>,
 {
     let lookup = &lookup.as_str();
-    let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
+    let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
     let name_vec: Vec<&Symbol> = iter_names.collect();
 
     let (case_insensitive_match, levenshtein_match) = name_vec
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 597e5b4..f6f1ad0 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -4,7 +4,6 @@
 use crate::token::{self, Token};
 use crate::tokenstream::TokenTree;
 
-use rustc_data_structures::sync::Lrc;
 use rustc_lexer::unescape::{unescape_byte, unescape_char};
 use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -108,7 +107,7 @@
                 });
                 error?;
                 buf.shrink_to_fit();
-                LitKind::ByteStr(Lrc::new(buf))
+                LitKind::ByteStr(buf.into())
             }
             token::ByteStrRaw(_) => {
                 let s = symbol.as_str();
@@ -128,7 +127,7 @@
                     symbol.to_string().into_bytes()
                 };
 
-                LitKind::ByteStr(Lrc::new(bytes))
+                LitKind::ByteStr(bytes.into())
             }
             token::Err => LitKind::Err(symbol),
         })
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 2ee9496..078dd4b 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -231,7 +231,6 @@
     }
 }
 
-pub const PREC_RESET: i8 = -100;
 pub const PREC_CLOSURE: i8 = -40;
 pub const PREC_JUMP: i8 = -30;
 pub const PREC_RANGE: i8 = -10;
@@ -283,6 +282,7 @@
     ForLoop,
     Loop,
     Match,
+    ConstBlock,
     Block,
     TryBlock,
     Struct,
@@ -347,6 +347,7 @@
             ExprPrecedence::ForLoop |
             ExprPrecedence::Loop |
             ExprPrecedence::Match |
+            ExprPrecedence::ConstBlock |
             ExprPrecedence::Block |
             ExprPrecedence::TryBlock |
             ExprPrecedence::Async |
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 86fd87f..507b496 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -200,11 +200,7 @@
         walk_generic_args(self, path_span, generic_args)
     }
     fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
-        match generic_arg {
-            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
-            GenericArg::Type(ty) => self.visit_ty(ty),
-            GenericArg::Const(ct) => self.visit_anon_const(ct),
-        }
+        walk_generic_arg(self, generic_arg)
     }
     fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
         walk_assoc_ty_constraint(self, constraint)
@@ -486,6 +482,17 @@
     }
 }
 
+pub fn walk_generic_arg<'a, V>(visitor: &mut V, generic_arg: &'a GenericArg)
+where
+    V: Visitor<'a>,
+{
+    match generic_arg {
+        GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
+        GenericArg::Type(ty) => visitor.visit_ty(ty),
+        GenericArg::Const(ct) => visitor.visit_anon_const(ct),
+    }
+}
+
 pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
     visitor: &mut V,
     constraint: &'a AssocTyConstraint,
@@ -717,6 +724,7 @@
         ExprKind::Array(ref subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }
+        ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
         ExprKind::Repeat(ref element, ref count) => {
             visitor.visit_expr(element);
             visitor.visit_anon_const(count)
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index c97f80c..c49fd76 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -30,6 +30,10 @@
             let kind = match e.kind {
                 ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
                 ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
+                ExprKind::ConstBlock(ref anon_const) => {
+                    let anon_const = self.lower_anon_const(anon_const);
+                    hir::ExprKind::ConstBlock(anon_const)
+                }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = self.lower_expr(expr);
                     let count = self.lower_anon_const(count);
@@ -432,17 +436,25 @@
         self.with_catch_scope(body.id, |this| {
             let mut block = this.lower_block_noalloc(body, true);
 
-            let try_span = this.mark_span_with_reason(
-                DesugaringKind::TryBlock,
-                body.span,
-                this.allow_try_trait.clone(),
-            );
-
             // Final expression of the block (if present) or `()` with span at the end of block
-            let tail_expr = block
-                .expr
-                .take()
-                .unwrap_or_else(|| this.expr_unit(this.sess.source_map().end_point(try_span)));
+            let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {
+                (
+                    this.mark_span_with_reason(
+                        DesugaringKind::TryBlock,
+                        expr.span,
+                        this.allow_try_trait.clone(),
+                    ),
+                    expr,
+                )
+            } else {
+                let try_span = this.mark_span_with_reason(
+                    DesugaringKind::TryBlock,
+                    this.sess.source_map().end_point(body.span),
+                    this.allow_try_trait.clone(),
+                );
+
+                (try_span, this.expr_unit(try_span))
+            };
 
             let ok_wrapped_span =
                 this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
@@ -977,7 +989,7 @@
                             asm::InlineAsmReg::parse(
                                 sess.asm_arch?,
                                 |feature| sess.target_features.contains(&Symbol::intern(feature)),
-                                &sess.target.target,
+                                &sess.target,
                                 s,
                             )
                             .map_err(|e| {
@@ -1178,52 +1190,47 @@
                                          input| {
                             match used_regs.entry(r) {
                                 Entry::Occupied(o) => {
-                                    if !skip {
-                                        skip = true;
-
-                                        let idx2 = *o.get();
-                                        let op2 = &operands[idx2];
-                                        let op_sp2 = asm.operands[idx2].1;
-                                        let reg2 = match op2.reg() {
-                                            Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
-                                            _ => unreachable!(),
-                                        };
-
-                                        let msg = format!(
-                                            "register `{}` conflicts with register `{}`",
-                                            reg.name(),
-                                            reg2.name()
-                                        );
-                                        let mut err = sess.struct_span_err(op_sp, &msg);
-                                        err.span_label(
-                                            op_sp,
-                                            &format!("register `{}`", reg.name()),
-                                        );
-                                        err.span_label(
-                                            op_sp2,
-                                            &format!("register `{}`", reg2.name()),
-                                        );
-
-                                        match (op, op2) {
-                                            (
-                                                hir::InlineAsmOperand::In { .. },
-                                                hir::InlineAsmOperand::Out { late, .. },
-                                            )
-                                            | (
-                                                hir::InlineAsmOperand::Out { late, .. },
-                                                hir::InlineAsmOperand::In { .. },
-                                            ) => {
-                                                assert!(!*late);
-                                                let out_op_sp = if input { op_sp2 } else { op_sp };
-                                                let msg = "use `lateout` instead of \
-                                                     `out` to avoid conflict";
-                                                err.span_help(out_op_sp, msg);
-                                            }
-                                            _ => {}
-                                        }
-
-                                        err.emit();
+                                    if skip {
+                                        return;
                                     }
+                                    skip = true;
+
+                                    let idx2 = *o.get();
+                                    let op2 = &operands[idx2];
+                                    let op_sp2 = asm.operands[idx2].1;
+                                    let reg2 = match op2.reg() {
+                                        Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r,
+                                        _ => unreachable!(),
+                                    };
+
+                                    let msg = format!(
+                                        "register `{}` conflicts with register `{}`",
+                                        reg.name(),
+                                        reg2.name()
+                                    );
+                                    let mut err = sess.struct_span_err(op_sp, &msg);
+                                    err.span_label(op_sp, &format!("register `{}`", reg.name()));
+                                    err.span_label(op_sp2, &format!("register `{}`", reg2.name()));
+
+                                    match (op, op2) {
+                                        (
+                                            hir::InlineAsmOperand::In { .. },
+                                            hir::InlineAsmOperand::Out { late, .. },
+                                        )
+                                        | (
+                                            hir::InlineAsmOperand::Out { late, .. },
+                                            hir::InlineAsmOperand::In { .. },
+                                        ) => {
+                                            assert!(!*late);
+                                            let out_op_sp = if input { op_sp2 } else { op_sp };
+                                            let msg = "use `lateout` instead of \
+                                                    `out` to avoid conflict";
+                                            err.span_help(out_op_sp, msg);
+                                        }
+                                        _ => {}
+                                    }
+
+                                    err.emit();
                                 }
                                 Entry::Vacant(v) => {
                                     v.insert(idx);
@@ -1553,7 +1560,7 @@
                 hir::LangItem::TryFromError,
                 unstable_span,
                 from_expr,
-                try_span,
+                unstable_span,
             );
             let thin_attrs = ThinVec::from(attrs);
             let catch_scope = self.catch_scopes.last().copied();
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 232ee35..b1c8e0e 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -287,7 +287,7 @@
     // ```
     fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
         match expr.kind {
-            ExprKind::Lit(..) | ExprKind::Err => {}
+            ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
             ExprKind::Path(..) if allow_paths => {}
             ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
             _ => self.err_handler().span_err(
@@ -796,7 +796,7 @@
 
     fn visit_expr(&mut self, expr: &'a Expr) {
         match &expr.kind {
-            ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => {
+            ExprKind::LlvmInlineAsm(..) if !self.session.target.options.allow_asm => {
                 struct_span_err!(
                     self.session,
                     expr.span,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 00d3db7..f200844 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -629,6 +629,7 @@
     gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
     gate_all!(const_trait_impl, "const trait impls are experimental");
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
+    gate_all!(inline_const, "inline-const is experimental");
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index ca7f127..56e769b 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -170,17 +170,11 @@
 
 impl Token {
     crate fn is_eof(&self) -> bool {
-        match *self {
-            Token::Eof => true,
-            _ => false,
-        }
+        matches!(self, Token::Eof)
     }
 
     pub fn is_hardbreak_tok(&self) -> bool {
-        match *self {
-            Token::Break(BreakToken { offset: 0, blank_space: bs }) if bs == SIZE_INFINITY => true,
-            _ => false,
-        }
+        matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
     }
 }
 
@@ -396,7 +390,7 @@
         self.scan_stack.pop_front().unwrap()
     }
 
-    fn scan_top(&mut self) -> usize {
+    fn scan_top(&self) -> usize {
         *self.scan_stack.front().unwrap()
     }
 
@@ -490,13 +484,10 @@
         self.pending_indentation += amount;
     }
 
-    fn get_top(&mut self) -> PrintStackElem {
-        match self.print_stack.last() {
-            Some(el) => *el,
-            None => {
-                PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
-            }
-        }
+    fn get_top(&self) -> PrintStackElem {
+        *self.print_stack.last().unwrap_or({
+            &PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
+        })
     }
 
     fn print_begin(&mut self, b: BeginToken, l: isize) {
diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs
deleted file mode 100644
index d16b541..0000000
--- a/compiler/rustc_ast_pretty/src/pprust.rs
+++ /dev/null
@@ -1,2864 +0,0 @@
-use crate::pp::Breaks::{Consistent, Inconsistent};
-use crate::pp::{self, Breaks};
-
-use rustc_ast::attr;
-use rustc_ast::ptr::P;
-use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_ast::util::classify;
-use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
-use rustc_ast::util::parser::{self, AssocOp, Fixity};
-use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs};
-use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
-use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
-use rustc_span::edition::Edition;
-use rustc_span::source_map::{SourceMap, Spanned};
-use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
-use rustc_span::{BytePos, FileName, Span};
-
-use std::borrow::Cow;
-
-#[cfg(test)]
-mod tests;
-
-pub enum MacHeader<'a> {
-    Path(&'a ast::Path),
-    Keyword(&'static str),
-}
-
-pub enum AnnNode<'a> {
-    Ident(&'a Ident),
-    Name(&'a Symbol),
-    Block(&'a ast::Block),
-    Item(&'a ast::Item),
-    SubItem(ast::NodeId),
-    Expr(&'a ast::Expr),
-    Pat(&'a ast::Pat),
-    Crate(&'a ast::Crate),
-}
-
-pub trait PpAnn {
-    fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
-    fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
-}
-
-#[derive(Copy, Clone)]
-pub struct NoAnn;
-
-impl PpAnn for NoAnn {}
-
-pub struct Comments<'a> {
-    sm: &'a SourceMap,
-    comments: Vec<Comment>,
-    current: usize,
-}
-
-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 }
-    }
-
-    pub fn next(&self) -> Option<Comment> {
-        self.comments.get(self.current).cloned()
-    }
-
-    pub fn trailing_comment(
-        &mut self,
-        span: rustc_span::Span,
-        next_pos: Option<BytePos>,
-    ) -> Option<Comment> {
-        if let Some(cmnt) = self.next() {
-            if cmnt.style != CommentStyle::Trailing {
-                return None;
-            }
-            let span_line = self.sm.lookup_char_pos(span.hi());
-            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);
-            }
-        }
-
-        None
-    }
-}
-
-pub struct State<'a> {
-    pub s: pp::Printer,
-    comments: Option<Comments<'a>>,
-    ann: &'a (dyn PpAnn + 'a),
-    is_expanded: bool,
-}
-
-crate const INDENT_UNIT: usize = 4;
-
-/// Requires you to pass an input filename and reader so that
-/// it can scan the input text for comments to copy forward.
-pub fn print_crate<'a>(
-    sm: &'a SourceMap,
-    krate: &ast::Crate,
-    filename: FileName,
-    input: String,
-    ann: &'a dyn PpAnn,
-    is_expanded: bool,
-    edition: Edition,
-    has_injected_crate: bool,
-) -> String {
-    let mut s = State {
-        s: pp::mk_printer(),
-        comments: Some(Comments::new(sm, filename, input)),
-        ann,
-        is_expanded,
-    };
-
-    if is_expanded && has_injected_crate {
-        // We need to print `#![no_std]` (and its feature gate) so that
-        // compiling pretty-printed source won't inject libstd again.
-        // However, we don't want these attributes in the AST because
-        // of the feature gate, so we fake them up here.
-
-        // `#![feature(prelude_import)]`
-        let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
-        let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
-        let fake_attr = attr::mk_attr_inner(list);
-        s.print_attribute(&fake_attr);
-
-        // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
-        // root, so this is not needed, and actually breaks things.
-        if edition == Edition::Edition2015 {
-            // `#![no_std]`
-            let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
-            let fake_attr = attr::mk_attr_inner(no_std_meta);
-            s.print_attribute(&fake_attr);
-        }
-    }
-
-    s.print_mod(&krate.module, &krate.attrs);
-    s.print_remaining_comments();
-    s.ann.post(&mut s, AnnNode::Crate(krate));
-    s.s.eof()
-}
-
-pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
-    let mut printer =
-        State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false };
-    f(&mut printer);
-    printer.s.eof()
-}
-
-// This makes printed token streams look slightly nicer,
-// and also addresses some specific regressions described in #63896 and #73345.
-fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
-    if let TokenTree::Token(token) = prev {
-        if let token::DocComment(comment_kind, ..) = token.kind {
-            return comment_kind != CommentKind::Line;
-        }
-    }
-    match tt {
-        TokenTree::Token(token) => match token.kind {
-            token::Comma => false,
-            _ => true,
-        },
-        TokenTree::Delimited(_, DelimToken::Paren, _) => match prev {
-            TokenTree::Token(token) => match token.kind {
-                token::Ident(_, _) => false,
-                _ => true,
-            },
-            _ => true,
-        },
-        TokenTree::Delimited(_, DelimToken::Bracket, _) => match prev {
-            TokenTree::Token(token) => match token.kind {
-                token::Pound => false,
-                _ => true,
-            },
-            _ => true,
-        },
-        TokenTree::Delimited(..) => true,
-    }
-}
-
-fn binop_to_string(op: BinOpToken) -> &'static str {
-    match op {
-        token::Plus => "+",
-        token::Minus => "-",
-        token::Star => "*",
-        token::Slash => "/",
-        token::Percent => "%",
-        token::Caret => "^",
-        token::And => "&",
-        token::Or => "|",
-        token::Shl => "<<",
-        token::Shr => ">>",
-    }
-}
-
-fn doc_comment_to_string(
-    comment_kind: CommentKind,
-    attr_style: ast::AttrStyle,
-    data: Symbol,
-) -> String {
-    match (comment_kind, attr_style) {
-        (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
-        (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
-        (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
-        (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
-    }
-}
-
-pub fn literal_to_string(lit: token::Lit) -> String {
-    let token::Lit { kind, symbol, suffix } = lit;
-    let mut out = match kind {
-        token::Byte => format!("b'{}'", symbol),
-        token::Char => format!("'{}'", symbol),
-        token::Str => format!("\"{}\"", symbol),
-        token::StrRaw(n) => {
-            format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
-        }
-        token::ByteStr => format!("b\"{}\"", symbol),
-        token::ByteStrRaw(n) => {
-            format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
-        }
-        token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
-    };
-
-    if let Some(suffix) = suffix {
-        out.push_str(&suffix.as_str())
-    }
-
-    out
-}
-
-/// Print the token kind precisely, without converting `$crate` into its respective crate name.
-pub fn token_kind_to_string(tok: &TokenKind) -> String {
-    token_kind_to_string_ext(tok, None)
-}
-
-fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String {
-    match *tok {
-        token::Eq => "=".to_string(),
-        token::Lt => "<".to_string(),
-        token::Le => "<=".to_string(),
-        token::EqEq => "==".to_string(),
-        token::Ne => "!=".to_string(),
-        token::Ge => ">=".to_string(),
-        token::Gt => ">".to_string(),
-        token::Not => "!".to_string(),
-        token::Tilde => "~".to_string(),
-        token::OrOr => "||".to_string(),
-        token::AndAnd => "&&".to_string(),
-        token::BinOp(op) => binop_to_string(op).to_string(),
-        token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
-
-        /* Structural symbols */
-        token::At => "@".to_string(),
-        token::Dot => ".".to_string(),
-        token::DotDot => "..".to_string(),
-        token::DotDotDot => "...".to_string(),
-        token::DotDotEq => "..=".to_string(),
-        token::Comma => ",".to_string(),
-        token::Semi => ";".to_string(),
-        token::Colon => ":".to_string(),
-        token::ModSep => "::".to_string(),
-        token::RArrow => "->".to_string(),
-        token::LArrow => "<-".to_string(),
-        token::FatArrow => "=>".to_string(),
-        token::OpenDelim(token::Paren) => "(".to_string(),
-        token::CloseDelim(token::Paren) => ")".to_string(),
-        token::OpenDelim(token::Bracket) => "[".to_string(),
-        token::CloseDelim(token::Bracket) => "]".to_string(),
-        token::OpenDelim(token::Brace) => "{".to_string(),
-        token::CloseDelim(token::Brace) => "}".to_string(),
-        token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(),
-        token::Pound => "#".to_string(),
-        token::Dollar => "$".to_string(),
-        token::Question => "?".to_string(),
-        token::SingleQuote => "'".to_string(),
-
-        /* Literals */
-        token::Literal(lit) => literal_to_string(lit),
-
-        /* Name components */
-        token::Ident(s, is_raw) => IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string(),
-        token::Lifetime(s) => s.to_string(),
-
-        /* Other */
-        token::DocComment(comment_kind, attr_style, data) => {
-            doc_comment_to_string(comment_kind, attr_style, data)
-        }
-        token::Eof => "<eof>".to_string(),
-
-        token::Interpolated(ref nt) => nonterminal_to_string(nt),
-    }
-}
-
-/// Print the token precisely, without converting `$crate` into its respective crate name.
-pub fn token_to_string(token: &Token) -> String {
-    token_to_string_ext(token, false)
-}
-
-fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
-    let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
-    token_kind_to_string_ext(&token.kind, convert_dollar_crate)
-}
-
-pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
-    match *nt {
-        token::NtExpr(ref e) => expr_to_string(e),
-        token::NtMeta(ref e) => attr_item_to_string(e),
-        token::NtTy(ref e) => ty_to_string(e),
-        token::NtPath(ref e) => path_to_string(e),
-        token::NtItem(ref e) => item_to_string(e),
-        token::NtBlock(ref e) => block_to_string(e),
-        token::NtStmt(ref e) => stmt_to_string(e),
-        token::NtPat(ref e) => pat_to_string(e),
-        token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
-        token::NtLifetime(e) => e.to_string(),
-        token::NtLiteral(ref e) => expr_to_string(e),
-        token::NtTT(ref tree) => tt_to_string(tree),
-        token::NtVis(ref e) => vis_to_string(e),
-    }
-}
-
-pub fn ty_to_string(ty: &ast::Ty) -> String {
-    to_string(|s| s.print_type(ty))
-}
-
-pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
-    to_string(|s| s.print_type_bounds("", bounds))
-}
-
-pub fn pat_to_string(pat: &ast::Pat) -> String {
-    to_string(|s| s.print_pat(pat))
-}
-
-pub fn expr_to_string(e: &ast::Expr) -> String {
-    to_string(|s| s.print_expr(e))
-}
-
-pub fn tt_to_string(tt: &TokenTree) -> String {
-    to_string(|s| s.print_tt(tt, false))
-}
-
-pub fn tts_to_string(tokens: &TokenStream) -> String {
-    to_string(|s| s.print_tts(tokens, false))
-}
-
-pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
-    to_string(|s| s.print_stmt(stmt))
-}
-
-pub fn item_to_string(i: &ast::Item) -> String {
-    to_string(|s| s.print_item(i))
-}
-
-pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
-    to_string(|s| s.print_generic_params(generic_params))
-}
-
-pub fn path_to_string(p: &ast::Path) -> String {
-    to_string(|s| s.print_path(p, false, 0))
-}
-
-pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
-    to_string(|s| s.print_path_segment(p, false))
-}
-
-pub fn vis_to_string(v: &ast::Visibility) -> String {
-    to_string(|s| s.print_visibility(v))
-}
-
-fn block_to_string(blk: &ast::Block) -> String {
-    to_string(|s| {
-        // Containing cbox, will be closed by `print_block` at `}`.
-        s.cbox(INDENT_UNIT);
-        // Head-ibox, will be closed by `print_block` after `{`.
-        s.ibox(0);
-        s.print_block(blk)
-    })
-}
-
-pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
-    to_string(|s| s.print_meta_list_item(li))
-}
-
-fn attr_item_to_string(ai: &ast::AttrItem) -> String {
-    to_string(|s| s.print_attr_item(ai, ai.path.span))
-}
-
-pub fn attribute_to_string(attr: &ast::Attribute) -> String {
-    to_string(|s| s.print_attribute(attr))
-}
-
-pub fn param_to_string(arg: &ast::Param) -> String {
-    to_string(|s| s.print_param(arg, false))
-}
-
-fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
-    format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
-}
-
-impl std::ops::Deref for State<'_> {
-    type Target = pp::Printer;
-    fn deref(&self) -> &Self::Target {
-        &self.s
-    }
-}
-
-impl std::ops::DerefMut for State<'_> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.s
-    }
-}
-
-pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
-    fn comments(&mut self) -> &mut Option<Comments<'a>>;
-    fn print_ident(&mut self, ident: Ident);
-    fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
-
-    fn strsep<T, F>(
-        &mut self,
-        sep: &'static str,
-        space_before: bool,
-        b: Breaks,
-        elts: &[T],
-        mut op: F,
-    ) where
-        F: FnMut(&mut Self, &T),
-    {
-        self.rbox(0, b);
-        if let Some((first, rest)) = elts.split_first() {
-            op(self, first);
-            for elt in rest {
-                if space_before {
-                    self.space();
-                }
-                self.word_space(sep);
-                op(self, elt);
-            }
-        }
-        self.end();
-    }
-
-    fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
-    where
-        F: FnMut(&mut Self, &T),
-    {
-        self.strsep(",", false, b, elts, op)
-    }
-
-    fn maybe_print_comment(&mut self, pos: BytePos) {
-        while let Some(ref cmnt) = self.next_comment() {
-            if cmnt.pos < pos {
-                self.print_comment(cmnt);
-            } else {
-                break;
-            }
-        }
-    }
-
-    fn print_comment(&mut self, cmnt: &Comment) {
-        match cmnt.style {
-            CommentStyle::Mixed => {
-                if !self.is_beginning_of_line() {
-                    self.zerobreak();
-                }
-                if let Some((last, lines)) = cmnt.lines.split_last() {
-                    self.ibox(0);
-
-                    for line in lines {
-                        self.word(line.clone());
-                        self.hardbreak()
-                    }
-
-                    self.word(last.clone());
-                    self.space();
-
-                    self.end();
-                }
-                self.zerobreak()
-            }
-            CommentStyle::Isolated => {
-                self.hardbreak_if_not_bol();
-                for line in &cmnt.lines {
-                    // Don't print empty lines because they will end up as trailing
-                    // whitespace.
-                    if !line.is_empty() {
-                        self.word(line.clone());
-                    }
-                    self.hardbreak();
-                }
-            }
-            CommentStyle::Trailing => {
-                if !self.is_beginning_of_line() {
-                    self.word(" ");
-                }
-                if cmnt.lines.len() == 1 {
-                    self.word(cmnt.lines[0].clone());
-                    self.hardbreak()
-                } else {
-                    self.ibox(0);
-                    for line in &cmnt.lines {
-                        if !line.is_empty() {
-                            self.word(line.clone());
-                        }
-                        self.hardbreak();
-                    }
-                    self.end();
-                }
-            }
-            CommentStyle::BlankLine => {
-                // We need to do at least one, possibly two hardbreaks.
-                let twice = match self.last_token() {
-                    pp::Token::String(s) => ";" == s,
-                    pp::Token::Begin(_) => true,
-                    pp::Token::End => true,
-                    _ => false,
-                };
-                if twice {
-                    self.hardbreak();
-                }
-                self.hardbreak();
-            }
-        }
-        if let Some(cmnts) = self.comments() {
-            cmnts.current += 1;
-        }
-    }
-
-    fn next_comment(&mut self) -> Option<Comment> {
-        self.comments().as_mut().and_then(|c| c.next())
-    }
-
-    fn print_literal(&mut self, lit: &ast::Lit) {
-        self.maybe_print_comment(lit.span.lo());
-        self.word(lit.token.to_string())
-    }
-
-    fn print_string(&mut self, st: &str, style: ast::StrStyle) {
-        let st = match style {
-            ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
-            ast::StrStyle::Raw(n) => {
-                format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
-            }
-        };
-        self.word(st)
-    }
-
-    fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
-        self.print_string(&sym.as_str(), style);
-    }
-
-    fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
-        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
-    }
-
-    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
-        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
-    }
-
-    fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
-        self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
-    }
-
-    fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
-        self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
-    }
-
-    fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
-        self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
-    }
-
-    fn print_either_attributes(
-        &mut self,
-        attrs: &[ast::Attribute],
-        kind: ast::AttrStyle,
-        is_inline: bool,
-        trailing_hardbreak: bool,
-    ) {
-        let mut count = 0;
-        for attr in attrs {
-            if attr.style == kind {
-                self.print_attribute_inline(attr, is_inline);
-                if is_inline {
-                    self.nbsp();
-                }
-                count += 1;
-            }
-        }
-        if count > 0 && trailing_hardbreak && !is_inline {
-            self.hardbreak_if_not_bol();
-        }
-    }
-
-    fn print_attribute(&mut self, attr: &ast::Attribute) {
-        self.print_attribute_inline(attr, false)
-    }
-
-    fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
-        if !is_inline {
-            self.hardbreak_if_not_bol();
-        }
-        self.maybe_print_comment(attr.span.lo());
-        match attr.kind {
-            ast::AttrKind::Normal(ref item) => {
-                match attr.style {
-                    ast::AttrStyle::Inner => self.word("#!["),
-                    ast::AttrStyle::Outer => self.word("#["),
-                }
-                self.print_attr_item(&item, attr.span);
-                self.word("]");
-            }
-            ast::AttrKind::DocComment(comment_kind, data) => {
-                self.word(doc_comment_to_string(comment_kind, attr.style, data));
-                self.hardbreak()
-            }
-        }
-    }
-
-    fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
-        self.ibox(0);
-        match &item.args {
-            MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
-                Some(MacHeader::Path(&item.path)),
-                false,
-                None,
-                delim.to_token(),
-                tokens,
-                true,
-                span,
-            ),
-            MacArgs::Empty | MacArgs::Eq(..) => {
-                self.print_path(&item.path, false, 0);
-                if let MacArgs::Eq(_, tokens) = &item.args {
-                    self.space();
-                    self.word_space("=");
-                    self.print_tts(tokens, true);
-                }
-            }
-        }
-        self.end();
-    }
-
-    fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
-        match item {
-            ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
-            ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
-        }
-    }
-
-    fn print_meta_item(&mut self, item: &ast::MetaItem) {
-        self.ibox(INDENT_UNIT);
-        match item.kind {
-            ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
-            ast::MetaItemKind::NameValue(ref value) => {
-                self.print_path(&item.path, false, 0);
-                self.space();
-                self.word_space("=");
-                self.print_literal(value);
-            }
-            ast::MetaItemKind::List(ref items) => {
-                self.print_path(&item.path, false, 0);
-                self.popen();
-                self.commasep(Consistent, &items[..], |s, i| s.print_meta_list_item(i));
-                self.pclose();
-            }
-        }
-        self.end();
-    }
-
-    /// This doesn't deserve to be called "pretty" printing, but it should be
-    /// meaning-preserving. A quick hack that might help would be to look at the
-    /// spans embedded in the TTs to decide where to put spaces and newlines.
-    /// But it'd be better to parse these according to the grammar of the
-    /// appropriate macro, transcribe back into the grammar we just parsed from,
-    /// and then pretty-print the resulting AST nodes (so, e.g., we print
-    /// expression arguments as expressions). It can be done! I think.
-    fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
-        match tt {
-            TokenTree::Token(token) => {
-                self.word(token_to_string_ext(&token, convert_dollar_crate));
-                if let token::DocComment(..) = token.kind {
-                    self.hardbreak()
-                }
-            }
-            TokenTree::Delimited(dspan, delim, tts) => {
-                self.print_mac_common(
-                    None,
-                    false,
-                    None,
-                    *delim,
-                    tts,
-                    convert_dollar_crate,
-                    dspan.entire(),
-                );
-            }
-        }
-    }
-
-    fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
-        let mut iter = tts.trees().peekable();
-        while let Some(tt) = iter.next() {
-            self.print_tt(&tt, convert_dollar_crate);
-            if let Some(next) = iter.peek() {
-                if tt_prepend_space(next, &tt) {
-                    self.space();
-                }
-            }
-        }
-    }
-
-    fn print_mac_common(
-        &mut self,
-        header: Option<MacHeader<'_>>,
-        has_bang: bool,
-        ident: Option<Ident>,
-        delim: DelimToken,
-        tts: &TokenStream,
-        convert_dollar_crate: bool,
-        span: Span,
-    ) {
-        if delim == DelimToken::Brace {
-            self.cbox(INDENT_UNIT);
-        }
-        match header {
-            Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
-            Some(MacHeader::Keyword(kw)) => self.word(kw),
-            None => {}
-        }
-        if has_bang {
-            self.word("!");
-        }
-        if let Some(ident) = ident {
-            self.nbsp();
-            self.print_ident(ident);
-        }
-        match delim {
-            DelimToken::Brace => {
-                if header.is_some() || has_bang || ident.is_some() {
-                    self.nbsp();
-                }
-                self.word("{");
-                if !tts.is_empty() {
-                    self.space();
-                }
-            }
-            _ => self.word(token_kind_to_string(&token::OpenDelim(delim))),
-        }
-        self.ibox(0);
-        self.print_tts(tts, convert_dollar_crate);
-        self.end();
-        match delim {
-            DelimToken::Brace => self.bclose(span),
-            _ => self.word(token_kind_to_string(&token::CloseDelim(delim))),
-        }
-    }
-
-    fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
-        self.maybe_print_comment(path.span.lo());
-
-        for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
-            if i > 0 {
-                self.word("::")
-            }
-            self.print_path_segment(segment, colons_before_params);
-        }
-    }
-
-    fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
-        if segment.ident.name != kw::PathRoot {
-            self.print_ident(segment.ident);
-            if let Some(ref args) = segment.args {
-                self.print_generic_args(args, colons_before_params);
-            }
-        }
-    }
-
-    fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
-        let w = w.into();
-        // Outer-box is consistent.
-        self.cbox(INDENT_UNIT);
-        // Head-box is inconsistent.
-        self.ibox(w.len() + 1);
-        // Keyword that starts the head.
-        if !w.is_empty() {
-            self.word_nbsp(w);
-        }
-    }
-
-    fn bopen(&mut self) {
-        self.word("{");
-        self.end(); // Close the head-box.
-    }
-
-    fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
-        self.maybe_print_comment(span.hi());
-        self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
-        self.word("}");
-        if close_box {
-            self.end(); // Close the outer-box.
-        }
-    }
-
-    fn bclose(&mut self, span: rustc_span::Span) {
-        self.bclose_maybe_open(span, true)
-    }
-
-    fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
-        if !self.is_beginning_of_line() {
-            self.break_offset(n, off)
-        } else {
-            if off != 0 && self.last_token().is_hardbreak_tok() {
-                // We do something pretty sketchy here: tuck the nonzero
-                // offset-adjustment we were going to deposit along with the
-                // break into the previous hardbreak.
-                self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
-            }
-        }
-    }
-}
-
-impl<'a> PrintState<'a> for State<'a> {
-    fn comments(&mut self) -> &mut Option<Comments<'a>> {
-        &mut self.comments
-    }
-
-    fn print_ident(&mut self, ident: Ident) {
-        self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
-        self.ann.post(self, AnnNode::Ident(&ident))
-    }
-
-    fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
-        if colons_before_params {
-            self.s.word("::")
-        }
-
-        match *args {
-            ast::GenericArgs::AngleBracketed(ref data) => {
-                self.s.word("<");
-                self.commasep(Inconsistent, &data.args, |s, arg| match arg {
-                    ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
-                    ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
-                });
-                self.s.word(">")
-            }
-
-            ast::GenericArgs::Parenthesized(ref data) => {
-                self.s.word("(");
-                self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
-                self.s.word(")");
-                self.print_fn_ret_ty(&data.output);
-            }
-        }
-    }
-}
-
-impl<'a> State<'a> {
-    // Synthesizes a comment that was not textually present in the original source
-    // file.
-    pub fn synth_comment(&mut self, text: String) {
-        self.s.word("/*");
-        self.s.space();
-        self.s.word(text);
-        self.s.space();
-        self.s.word("*/")
-    }
-
-    crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
-    where
-        F: FnMut(&mut State<'_>, &T),
-        G: FnMut(&T) -> rustc_span::Span,
-    {
-        self.rbox(0, b);
-        let len = elts.len();
-        let mut i = 0;
-        for elt in elts {
-            self.maybe_print_comment(get_span(elt).hi());
-            op(self, elt);
-            i += 1;
-            if i < len {
-                self.s.word(",");
-                self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
-                self.space_if_not_bol();
-            }
-        }
-        self.end();
-    }
-
-    crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
-        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
-    }
-
-    pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) {
-        self.print_inner_attributes(attrs);
-        for item in &_mod.items {
-            self.print_item(item);
-        }
-    }
-
-    crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
-        self.print_inner_attributes(attrs);
-        for item in &nmod.items {
-            self.print_foreign_item(item);
-        }
-    }
-
-    pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
-        if let Some(lt) = *lifetime {
-            self.print_lifetime(lt);
-            self.nbsp();
-        }
-    }
-
-    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
-        self.print_ident(constraint.ident);
-        self.s.space();
-        match &constraint.kind {
-            ast::AssocTyConstraintKind::Equality { ty } => {
-                self.word_space("=");
-                self.print_type(ty);
-            }
-            ast::AssocTyConstraintKind::Bound { bounds } => {
-                self.print_type_bounds(":", &*bounds);
-            }
-        }
-    }
-
-    pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
-        match generic_arg {
-            GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
-            GenericArg::Type(ty) => self.print_type(ty),
-            GenericArg::Const(ct) => self.print_expr(&ct.value),
-        }
-    }
-
-    pub fn print_type(&mut self, ty: &ast::Ty) {
-        self.maybe_print_comment(ty.span.lo());
-        self.ibox(0);
-        match ty.kind {
-            ast::TyKind::Slice(ref ty) => {
-                self.s.word("[");
-                self.print_type(ty);
-                self.s.word("]");
-            }
-            ast::TyKind::Ptr(ref mt) => {
-                self.s.word("*");
-                self.print_mt(mt, true);
-            }
-            ast::TyKind::Rptr(ref lifetime, ref mt) => {
-                self.s.word("&");
-                self.print_opt_lifetime(lifetime);
-                self.print_mt(mt, false);
-            }
-            ast::TyKind::Never => {
-                self.s.word("!");
-            }
-            ast::TyKind::Tup(ref elts) => {
-                self.popen();
-                self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(ty));
-                if elts.len() == 1 {
-                    self.s.word(",");
-                }
-                self.pclose();
-            }
-            ast::TyKind::Paren(ref typ) => {
-                self.popen();
-                self.print_type(typ);
-                self.pclose();
-            }
-            ast::TyKind::BareFn(ref f) => {
-                self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
-            }
-            ast::TyKind::Path(None, ref path) => {
-                self.print_path(path, false, 0);
-            }
-            ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
-            ast::TyKind::TraitObject(ref bounds, syntax) => {
-                let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
-                self.print_type_bounds(prefix, &bounds[..]);
-            }
-            ast::TyKind::ImplTrait(_, ref bounds) => {
-                self.print_type_bounds("impl", &bounds[..]);
-            }
-            ast::TyKind::Array(ref ty, ref length) => {
-                self.s.word("[");
-                self.print_type(ty);
-                self.s.word("; ");
-                self.print_expr(&length.value);
-                self.s.word("]");
-            }
-            ast::TyKind::Typeof(ref e) => {
-                self.s.word("typeof(");
-                self.print_expr(&e.value);
-                self.s.word(")");
-            }
-            ast::TyKind::Infer => {
-                self.s.word("_");
-            }
-            ast::TyKind::Err => {
-                self.popen();
-                self.s.word("/*ERROR*/");
-                self.pclose();
-            }
-            ast::TyKind::ImplicitSelf => {
-                self.s.word("Self");
-            }
-            ast::TyKind::MacCall(ref m) => {
-                self.print_mac(m);
-            }
-            ast::TyKind::CVarArgs => {
-                self.s.word("...");
-            }
-        }
-        self.end();
-    }
-
-    crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
-        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
-        self.ann.pre(self, AnnNode::SubItem(id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(span.lo());
-        self.print_outer_attributes(attrs);
-        match kind {
-            ast::ForeignItemKind::Fn(def, sig, gen, body) => {
-                self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
-            }
-            ast::ForeignItemKind::Static(ty, mutbl, body) => {
-                let def = ast::Defaultness::Final;
-                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
-            }
-            ast::ForeignItemKind::TyAlias(def, generics, bounds, ty) => {
-                self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
-            }
-            ast::ForeignItemKind::MacCall(m) => {
-                self.print_mac(m);
-                if m.args.need_semicolon() {
-                    self.s.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(id))
-    }
-
-    fn print_item_const(
-        &mut self,
-        ident: Ident,
-        mutbl: Option<ast::Mutability>,
-        ty: &ast::Ty,
-        body: Option<&ast::Expr>,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-    ) {
-        self.head("");
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        let leading = match mutbl {
-            None => "const",
-            Some(ast::Mutability::Not) => "static",
-            Some(ast::Mutability::Mut) => "static mut",
-        };
-        self.word_space(leading);
-        self.print_ident(ident);
-        self.word_space(":");
-        self.print_type(ty);
-        self.s.space();
-        self.end(); // end the head-ibox
-        if let Some(body) = body {
-            self.word_space("=");
-            self.print_expr(body);
-        }
-        self.s.word(";");
-        self.end(); // end the outer cbox
-    }
-
-    fn print_associated_type(
-        &mut self,
-        ident: Ident,
-        generics: &ast::Generics,
-        bounds: &ast::GenericBounds,
-        ty: Option<&ast::Ty>,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-    ) {
-        self.head("");
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        self.word_space("type");
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        self.print_type_bounds(":", bounds);
-        self.print_where_clause(&generics.where_clause);
-        if let Some(ty) = ty {
-            self.s.space();
-            self.word_space("=");
-            self.print_type(ty);
-        }
-        self.s.word(";");
-        self.end(); // end inner head-block
-        self.end(); // end outer head-block
-    }
-
-    /// Pretty-prints an item.
-    crate fn print_item(&mut self, item: &ast::Item) {
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(item.span.lo());
-        self.print_outer_attributes(&item.attrs);
-        self.ann.pre(self, AnnNode::Item(item));
-        match item.kind {
-            ast::ItemKind::ExternCrate(orig_name) => {
-                self.head(visibility_qualified(&item.vis, "extern crate"));
-                if let Some(orig_name) = orig_name {
-                    self.print_name(orig_name);
-                    self.s.space();
-                    self.s.word("as");
-                    self.s.space();
-                }
-                self.print_ident(item.ident);
-                self.s.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
-            }
-            ast::ItemKind::Use(ref tree) => {
-                self.head(visibility_qualified(&item.vis, "use"));
-                self.print_use_tree(tree);
-                self.s.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
-            }
-            ast::ItemKind::Static(ref ty, mutbl, ref body) => {
-                let def = ast::Defaultness::Final;
-                self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
-            }
-            ast::ItemKind::Const(def, ref ty, ref body) => {
-                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
-            }
-            ast::ItemKind::Fn(def, ref sig, ref gen, ref body) => {
-                let body = body.as_deref();
-                self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
-            }
-            ast::ItemKind::Mod(ref _mod) => {
-                self.head(to_string(|s| {
-                    s.print_visibility(&item.vis);
-                    s.print_unsafety(_mod.unsafety);
-                    s.word("mod");
-                }));
-                self.print_ident(item.ident);
-
-                if _mod.inline || self.is_expanded {
-                    self.nbsp();
-                    self.bopen();
-                    self.print_mod(_mod, &item.attrs);
-                    self.bclose(item.span);
-                } else {
-                    self.s.word(";");
-                    self.end(); // end inner head-block
-                    self.end(); // end outer head-block
-                }
-            }
-            ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head(to_string(|s| {
-                    s.print_unsafety(nmod.unsafety);
-                    s.word("extern");
-                }));
-                if let Some(abi) = nmod.abi {
-                    self.print_literal(&abi.as_lit());
-                    self.nbsp();
-                }
-                self.bopen();
-                self.print_foreign_mod(nmod, &item.attrs);
-                self.bclose(item.span);
-            }
-            ast::ItemKind::GlobalAsm(ref ga) => {
-                self.head(visibility_qualified(&item.vis, "global_asm!"));
-                self.s.word(ga.asm.to_string());
-                self.end();
-            }
-            ast::ItemKind::TyAlias(def, ref generics, ref bounds, ref ty) => {
-                let ty = ty.as_deref();
-                self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
-            }
-            ast::ItemKind::Enum(ref enum_definition, ref params) => {
-                self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
-            }
-            ast::ItemKind::Struct(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "struct"));
-                self.print_struct(struct_def, generics, item.ident, item.span, true);
-            }
-            ast::ItemKind::Union(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "union"));
-                self.print_struct(struct_def, generics, item.ident, item.span, true);
-            }
-            ast::ItemKind::Impl {
-                unsafety,
-                polarity,
-                defaultness,
-                constness,
-                ref generics,
-                ref of_trait,
-                ref self_ty,
-                ref items,
-            } => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.print_defaultness(defaultness);
-                self.print_unsafety(unsafety);
-                self.word_nbsp("impl");
-                self.print_constness(constness);
-
-                if !generics.params.is_empty() {
-                    self.print_generic_params(&generics.params);
-                    self.s.space();
-                }
-
-                if let ast::ImplPolarity::Negative(_) = polarity {
-                    self.s.word("!");
-                }
-
-                if let Some(ref t) = *of_trait {
-                    self.print_trait_ref(t);
-                    self.s.space();
-                    self.word_space("for");
-                }
-
-                self.print_type(self_ty);
-                self.print_where_clause(&generics.where_clause);
-
-                self.s.space();
-                self.bopen();
-                self.print_inner_attributes(&item.attrs);
-                for impl_item in items {
-                    self.print_assoc_item(impl_item);
-                }
-                self.bclose(item.span);
-            }
-            ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.print_unsafety(unsafety);
-                self.print_is_auto(is_auto);
-                self.word_nbsp("trait");
-                self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        self.s.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b.clone());
-                    }
-                }
-                self.print_type_bounds(":", &real_bounds[..]);
-                self.print_where_clause(&generics.where_clause);
-                self.s.word(" ");
-                self.bopen();
-                self.print_inner_attributes(&item.attrs);
-                for trait_item in trait_items {
-                    self.print_assoc_item(trait_item);
-                }
-                self.bclose(item.span);
-            }
-            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.word_nbsp("trait");
-                self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                // FIXME(durka) this seems to be some quite outdated syntax
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        self.s.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b.clone());
-                    }
-                }
-                self.nbsp();
-                self.print_type_bounds("=", &real_bounds[..]);
-                self.print_where_clause(&generics.where_clause);
-                self.s.word(";");
-            }
-            ast::ItemKind::MacCall(ref mac) => {
-                self.print_mac(mac);
-                if mac.args.need_semicolon() {
-                    self.s.word(";");
-                }
-            }
-            ast::ItemKind::MacroDef(ref macro_def) => {
-                let (kw, has_bang) = if macro_def.macro_rules {
-                    ("macro_rules", true)
-                } else {
-                    self.print_visibility(&item.vis);
-                    ("macro", false)
-                };
-                self.print_mac_common(
-                    Some(MacHeader::Keyword(kw)),
-                    has_bang,
-                    Some(item.ident),
-                    macro_def.body.delim(),
-                    &macro_def.body.inner_tokens(),
-                    true,
-                    item.span,
-                );
-            }
-        }
-        self.ann.post(self, AnnNode::Item(item))
-    }
-
-    fn print_trait_ref(&mut self, t: &ast::TraitRef) {
-        self.print_path(&t.path, false, 0)
-    }
-
-    fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
-        if !generic_params.is_empty() {
-            self.s.word("for");
-            self.print_generic_params(generic_params);
-            self.nbsp();
-        }
-    }
-
-    fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
-        self.print_formal_generic_params(&t.bound_generic_params);
-        self.print_trait_ref(&t.trait_ref)
-    }
-
-    crate fn print_enum_def(
-        &mut self,
-        enum_definition: &ast::EnumDef,
-        generics: &ast::Generics,
-        ident: Ident,
-        span: rustc_span::Span,
-        visibility: &ast::Visibility,
-    ) {
-        self.head(visibility_qualified(visibility, "enum"));
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        self.print_where_clause(&generics.where_clause);
-        self.s.space();
-        self.print_variants(&enum_definition.variants, span)
-    }
-
-    crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
-        self.bopen();
-        for v in variants {
-            self.space_if_not_bol();
-            self.maybe_print_comment(v.span.lo());
-            self.print_outer_attributes(&v.attrs);
-            self.ibox(INDENT_UNIT);
-            self.print_variant(v);
-            self.s.word(",");
-            self.end();
-            self.maybe_print_trailing_comment(v.span, None);
-        }
-        self.bclose(span)
-    }
-
-    crate fn print_visibility(&mut self, vis: &ast::Visibility) {
-        match vis.kind {
-            ast::VisibilityKind::Public => self.word_nbsp("pub"),
-            ast::VisibilityKind::Crate(sugar) => match sugar {
-                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
-                ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
-            },
-            ast::VisibilityKind::Restricted { ref path, .. } => {
-                let path = to_string(|s| s.print_path(path, false, 0));
-                if path == "self" || path == "super" {
-                    self.word_nbsp(format!("pub({})", path))
-                } else {
-                    self.word_nbsp(format!("pub(in {})", path))
-                }
-            }
-            ast::VisibilityKind::Inherited => {}
-        }
-    }
-
-    crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
-        if let ast::Defaultness::Default(_) = defaultness {
-            self.word_nbsp("default");
-        }
-    }
-
-    crate fn print_struct(
-        &mut self,
-        struct_def: &ast::VariantData,
-        generics: &ast::Generics,
-        ident: Ident,
-        span: rustc_span::Span,
-        print_finalizer: bool,
-    ) {
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        match struct_def {
-            ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
-                if let ast::VariantData::Tuple(..) = struct_def {
-                    self.popen();
-                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
-                        s.maybe_print_comment(field.span.lo());
-                        s.print_outer_attributes(&field.attrs);
-                        s.print_visibility(&field.vis);
-                        s.print_type(&field.ty)
-                    });
-                    self.pclose();
-                }
-                self.print_where_clause(&generics.where_clause);
-                if print_finalizer {
-                    self.s.word(";");
-                }
-                self.end();
-                self.end(); // Close the outer-box.
-            }
-            ast::VariantData::Struct(..) => {
-                self.print_where_clause(&generics.where_clause);
-                self.nbsp();
-                self.bopen();
-                self.hardbreak_if_not_bol();
-
-                for field in struct_def.fields() {
-                    self.hardbreak_if_not_bol();
-                    self.maybe_print_comment(field.span.lo());
-                    self.print_outer_attributes(&field.attrs);
-                    self.print_visibility(&field.vis);
-                    self.print_ident(field.ident.unwrap());
-                    self.word_nbsp(":");
-                    self.print_type(&field.ty);
-                    self.s.word(",");
-                }
-
-                self.bclose(span)
-            }
-        }
-    }
-
-    crate fn print_variant(&mut self, v: &ast::Variant) {
-        self.head("");
-        self.print_visibility(&v.vis);
-        let generics = ast::Generics::default();
-        self.print_struct(&v.data, &generics, v.ident, v.span, false);
-        if let Some(ref d) = v.disr_expr {
-            self.s.space();
-            self.word_space("=");
-            self.print_expr(&d.value)
-        }
-    }
-
-    crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
-        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
-        self.ann.pre(self, AnnNode::SubItem(id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(span.lo());
-        self.print_outer_attributes(attrs);
-        match kind {
-            ast::AssocItemKind::Fn(def, sig, gen, body) => {
-                self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
-            }
-            ast::AssocItemKind::Const(def, ty, body) => {
-                self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
-            }
-            ast::AssocItemKind::TyAlias(def, generics, bounds, ty) => {
-                self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
-            }
-            ast::AssocItemKind::MacCall(m) => {
-                self.print_mac(m);
-                if m.args.need_semicolon() {
-                    self.s.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(id))
-    }
-
-    crate fn print_stmt(&mut self, st: &ast::Stmt) {
-        self.maybe_print_comment(st.span.lo());
-        match st.kind {
-            ast::StmtKind::Local(ref loc) => {
-                self.print_outer_attributes(&loc.attrs);
-                self.space_if_not_bol();
-                self.ibox(INDENT_UNIT);
-                self.word_nbsp("let");
-
-                self.ibox(INDENT_UNIT);
-                self.print_local_decl(loc);
-                self.end();
-                if let Some(ref init) = loc.init {
-                    self.nbsp();
-                    self.word_space("=");
-                    self.print_expr(init);
-                }
-                self.s.word(";");
-                self.end();
-            }
-            ast::StmtKind::Item(ref item) => self.print_item(item),
-            ast::StmtKind::Expr(ref expr) => {
-                self.space_if_not_bol();
-                self.print_expr_outer_attr_style(expr, false);
-                if classify::expr_requires_semi_to_be_stmt(expr) {
-                    self.s.word(";");
-                }
-            }
-            ast::StmtKind::Semi(ref expr) => {
-                self.space_if_not_bol();
-                self.print_expr_outer_attr_style(expr, false);
-                self.s.word(";");
-            }
-            ast::StmtKind::Empty => {
-                self.space_if_not_bol();
-                self.s.word(";");
-            }
-            ast::StmtKind::MacCall(ref mac) => {
-                self.space_if_not_bol();
-                self.print_outer_attributes(&mac.attrs);
-                self.print_mac(&mac.mac);
-                if mac.style == ast::MacStmtStyle::Semicolon {
-                    self.s.word(";");
-                }
-            }
-        }
-        self.maybe_print_trailing_comment(st.span, None)
-    }
-
-    crate fn print_block(&mut self, blk: &ast::Block) {
-        self.print_block_with_attrs(blk, &[])
-    }
-
-    crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
-        self.print_block_maybe_unclosed(blk, &[], false)
-    }
-
-    crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
-        self.print_block_maybe_unclosed(blk, attrs, true)
-    }
-
-    crate fn print_block_maybe_unclosed(
-        &mut self,
-        blk: &ast::Block,
-        attrs: &[ast::Attribute],
-        close_box: bool,
-    ) {
-        match blk.rules {
-            BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
-            BlockCheckMode::Default => (),
-        }
-        self.maybe_print_comment(blk.span.lo());
-        self.ann.pre(self, AnnNode::Block(blk));
-        self.bopen();
-
-        self.print_inner_attributes(attrs);
-
-        for (i, st) in blk.stmts.iter().enumerate() {
-            match st.kind {
-                ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
-                    self.maybe_print_comment(st.span.lo());
-                    self.space_if_not_bol();
-                    self.print_expr_outer_attr_style(expr, false);
-                    self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
-                }
-                _ => self.print_stmt(st),
-            }
-        }
-
-        self.bclose_maybe_open(blk.span, close_box);
-        self.ann.post(self, AnnNode::Block(blk))
-    }
-
-    /// Print a `let pat = scrutinee` expression.
-    crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
-        self.s.word("let ");
-
-        self.print_pat(pat);
-        self.s.space();
-
-        self.word_space("=");
-        self.print_expr_cond_paren(
-            scrutinee,
-            Self::cond_needs_par(scrutinee)
-                || parser::needs_par_as_let_scrutinee(scrutinee.precedence().order()),
-        )
-    }
-
-    fn print_else(&mut self, els: Option<&ast::Expr>) {
-        if let Some(_else) = els {
-            match _else.kind {
-                // Another `else if` block.
-                ast::ExprKind::If(ref i, ref then, ref e) => {
-                    self.cbox(INDENT_UNIT - 1);
-                    self.ibox(0);
-                    self.s.word(" else if ");
-                    self.print_expr_as_cond(i);
-                    self.s.space();
-                    self.print_block(then);
-                    self.print_else(e.as_deref())
-                }
-                // Final `else` block.
-                ast::ExprKind::Block(ref b, _) => {
-                    self.cbox(INDENT_UNIT - 1);
-                    self.ibox(0);
-                    self.s.word(" else ");
-                    self.print_block(b)
-                }
-                // Constraints would be great here!
-                _ => {
-                    panic!("print_if saw if with weird alternative");
-                }
-            }
-        }
-    }
-
-    crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
-        self.head("if");
-
-        self.print_expr_as_cond(test);
-        self.s.space();
-
-        self.print_block(blk);
-        self.print_else(elseopt)
-    }
-
-    crate fn print_mac(&mut self, m: &ast::MacCall) {
-        self.print_mac_common(
-            Some(MacHeader::Path(&m.path)),
-            true,
-            None,
-            m.args.delim(),
-            &m.args.inner_tokens(),
-            true,
-            m.span(),
-        );
-    }
-
-    fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
-        self.popen();
-        self.commasep_exprs(Inconsistent, args);
-        self.pclose()
-    }
-
-    crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
-        self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
-    }
-
-    /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
-    /// `if cond { ... }`.
-    crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
-        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
-    }
-
-    /// Does `expr` need parenthesis when printed in a condition position?
-    fn cond_needs_par(expr: &ast::Expr) -> bool {
-        match expr.kind {
-            // These cases need parens due to the parse error observed in #26461: `if return {}`
-            // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
-            ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Break(..) => true,
-
-            _ => parser::contains_exterior_struct_lit(expr),
-        }
-    }
-
-    /// Prints `expr` or `(expr)` when `needs_par` holds.
-    fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
-        if needs_par {
-            self.popen();
-        }
-        self.print_expr(expr);
-        if needs_par {
-            self.pclose();
-        }
-    }
-
-    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
-        self.ibox(INDENT_UNIT);
-        self.s.word("[");
-        self.print_inner_attributes_inline(attrs);
-        self.commasep_exprs(Inconsistent, &exprs[..]);
-        self.s.word("]");
-        self.end();
-    }
-
-    fn print_expr_repeat(
-        &mut self,
-        element: &ast::Expr,
-        count: &ast::AnonConst,
-        attrs: &[ast::Attribute],
-    ) {
-        self.ibox(INDENT_UNIT);
-        self.s.word("[");
-        self.print_inner_attributes_inline(attrs);
-        self.print_expr(element);
-        self.word_space(";");
-        self.print_expr(&count.value);
-        self.s.word("]");
-        self.end();
-    }
-
-    fn print_expr_struct(
-        &mut self,
-        path: &ast::Path,
-        fields: &[ast::Field],
-        wth: &Option<P<ast::Expr>>,
-        attrs: &[ast::Attribute],
-    ) {
-        self.print_path(path, true, 0);
-        self.s.word("{");
-        self.print_inner_attributes_inline(attrs);
-        self.commasep_cmnt(
-            Consistent,
-            &fields[..],
-            |s, field| {
-                s.print_outer_attributes(&field.attrs);
-                s.ibox(INDENT_UNIT);
-                if !field.is_shorthand {
-                    s.print_ident(field.ident);
-                    s.word_space(":");
-                }
-                s.print_expr(&field.expr);
-                s.end();
-            },
-            |f| f.span,
-        );
-        match *wth {
-            Some(ref expr) => {
-                self.ibox(INDENT_UNIT);
-                if !fields.is_empty() {
-                    self.s.word(",");
-                    self.s.space();
-                }
-                self.s.word("..");
-                self.print_expr(expr);
-                self.end();
-            }
-            _ => {
-                if !fields.is_empty() {
-                    self.s.word(",")
-                }
-            }
-        }
-        self.s.word("}");
-    }
-
-    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
-        self.popen();
-        self.print_inner_attributes_inline(attrs);
-        self.commasep_exprs(Inconsistent, &exprs[..]);
-        if exprs.len() == 1 {
-            self.s.word(",");
-        }
-        self.pclose()
-    }
-
-    fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
-        let prec = match func.kind {
-            ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
-            _ => parser::PREC_POSTFIX,
-        };
-
-        self.print_expr_maybe_paren(func, prec);
-        self.print_call_post(args)
-    }
-
-    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
-        let base_args = &args[1..];
-        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
-        self.s.word(".");
-        self.print_ident(segment.ident);
-        if let Some(ref args) = segment.args {
-            self.print_generic_args(args, true);
-        }
-        self.print_call_post(base_args)
-    }
-
-    fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
-        let assoc_op = AssocOp::from_ast_binop(op.node);
-        let prec = assoc_op.precedence() as i8;
-        let fixity = assoc_op.fixity();
-
-        let (left_prec, right_prec) = match fixity {
-            Fixity::Left => (prec, prec + 1),
-            Fixity::Right => (prec + 1, prec),
-            Fixity::None => (prec + 1, prec + 1),
-        };
-
-        let left_prec = match (&lhs.kind, op.node) {
-            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
-            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
-            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
-            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
-                parser::PREC_FORCE_PAREN
-            }
-            // We are given `(let _ = a) OP b`.
-            //
-            // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
-            //   as the parser will interpret this as `(let _ = a) OP b`.
-            //
-            // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
-            //   parens are required since the parser would interpret `let a = b < c` as
-            //   `let a = (b < c)`. To achieve this, we force parens.
-            (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
-                parser::PREC_FORCE_PAREN
-            }
-            _ => left_prec,
-        };
-
-        self.print_expr_maybe_paren(lhs, left_prec);
-        self.s.space();
-        self.word_space(op.node.to_string());
-        self.print_expr_maybe_paren(rhs, right_prec)
-    }
-
-    fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
-        self.s.word(ast::UnOp::to_string(op));
-        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
-    }
-
-    fn print_expr_addr_of(
-        &mut self,
-        kind: ast::BorrowKind,
-        mutability: ast::Mutability,
-        expr: &ast::Expr,
-    ) {
-        self.s.word("&");
-        match kind {
-            ast::BorrowKind::Ref => self.print_mutability(mutability, false),
-            ast::BorrowKind::Raw => {
-                self.word_nbsp("raw");
-                self.print_mutability(mutability, true);
-            }
-        }
-        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
-    }
-
-    pub fn print_expr(&mut self, expr: &ast::Expr) {
-        self.print_expr_outer_attr_style(expr, true)
-    }
-
-    fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
-        self.maybe_print_comment(expr.span.lo());
-
-        let attrs = &expr.attrs;
-        if is_inline {
-            self.print_outer_attributes_inline(attrs);
-        } else {
-            self.print_outer_attributes(attrs);
-        }
-
-        self.ibox(INDENT_UNIT);
-        self.ann.pre(self, AnnNode::Expr(expr));
-        match expr.kind {
-            ast::ExprKind::Box(ref expr) => {
-                self.word_space("box");
-                self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
-            }
-            ast::ExprKind::Array(ref exprs) => {
-                self.print_expr_vec(&exprs[..], attrs);
-            }
-            ast::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(element, count, attrs);
-            }
-            ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
-                self.print_expr_struct(path, &fields[..], wth, attrs);
-            }
-            ast::ExprKind::Tup(ref exprs) => {
-                self.print_expr_tup(&exprs[..], attrs);
-            }
-            ast::ExprKind::Call(ref func, ref args) => {
-                self.print_expr_call(func, &args[..]);
-            }
-            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
-                self.print_expr_method_call(segment, &args[..]);
-            }
-            ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
-                self.print_expr_binary(op, lhs, rhs);
-            }
-            ast::ExprKind::Unary(op, ref expr) => {
-                self.print_expr_unary(op, expr);
-            }
-            ast::ExprKind::AddrOf(k, m, ref expr) => {
-                self.print_expr_addr_of(k, m, expr);
-            }
-            ast::ExprKind::Lit(ref lit) => {
-                self.print_literal(lit);
-            }
-            ast::ExprKind::Cast(ref expr, ref ty) => {
-                let prec = AssocOp::As.precedence() as i8;
-                self.print_expr_maybe_paren(expr, prec);
-                self.s.space();
-                self.word_space("as");
-                self.print_type(ty);
-            }
-            ast::ExprKind::Type(ref expr, ref ty) => {
-                let prec = AssocOp::Colon.precedence() as i8;
-                self.print_expr_maybe_paren(expr, prec);
-                self.word_space(":");
-                self.print_type(ty);
-            }
-            ast::ExprKind::Let(ref pat, ref scrutinee) => {
-                self.print_let(pat, scrutinee);
-            }
-            ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                self.print_if(test, blk, elseopt.as_deref())
-            }
-            ast::ExprKind::While(ref test, ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("while");
-                self.print_expr_as_cond(test);
-                self.s.space();
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("for");
-                self.print_pat(pat);
-                self.s.space();
-                self.word_space("in");
-                self.print_expr_as_cond(iter);
-                self.s.space();
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Loop(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("loop");
-                self.s.space();
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Match(ref expr, ref arms) => {
-                self.cbox(INDENT_UNIT);
-                self.ibox(INDENT_UNIT);
-                self.word_nbsp("match");
-                self.print_expr_as_cond(expr);
-                self.s.space();
-                self.bopen();
-                self.print_inner_attributes_no_trailing_hardbreak(attrs);
-                for arm in arms {
-                    self.print_arm(arm);
-                }
-                self.bclose(expr.span);
-            }
-            ast::ExprKind::Closure(
-                capture_clause,
-                asyncness,
-                movability,
-                ref decl,
-                ref body,
-                _,
-            ) => {
-                self.print_movability(movability);
-                self.print_asyncness(asyncness);
-                self.print_capture_clause(capture_clause);
-
-                self.print_fn_params_and_ret(decl, true);
-                self.s.space();
-                self.print_expr(body);
-                self.end(); // need to close a box
-
-                // a box will be closed by print_expr, but we didn't want an overall
-                // wrapper so we closed the corresponding opening. so create an
-                // empty box to satisfy the close.
-                self.ibox(0);
-            }
-            ast::ExprKind::Block(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                // containing cbox, will be closed by print-block at }
-                self.cbox(INDENT_UNIT);
-                // head-box, will be closed by print-block after {
-                self.ibox(0);
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Async(capture_clause, _, ref blk) => {
-                self.word_nbsp("async");
-                self.print_capture_clause(capture_clause);
-                self.s.space();
-                // cbox/ibox in analogy to the `ExprKind::Block` arm above
-                self.cbox(INDENT_UNIT);
-                self.ibox(0);
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Await(ref expr) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.s.word(".await");
-            }
-            ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
-                let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(lhs, prec + 1);
-                self.s.space();
-                self.word_space("=");
-                self.print_expr_maybe_paren(rhs, prec);
-            }
-            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(lhs, prec + 1);
-                self.s.space();
-                self.s.word(op.node.to_string());
-                self.word_space("=");
-                self.print_expr_maybe_paren(rhs, prec);
-            }
-            ast::ExprKind::Field(ref expr, ident) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.s.word(".");
-                self.print_ident(ident);
-            }
-            ast::ExprKind::Index(ref expr, ref index) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.s.word("[");
-                self.print_expr(index);
-                self.s.word("]");
-            }
-            ast::ExprKind::Range(ref start, ref end, limits) => {
-                // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
-                // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
-                // Here we use a fake precedence value so that any child with lower precedence than
-                // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
-                let fake_prec = AssocOp::LOr.precedence() as i8;
-                if let Some(ref e) = *start {
-                    self.print_expr_maybe_paren(e, fake_prec);
-                }
-                if limits == ast::RangeLimits::HalfOpen {
-                    self.s.word("..");
-                } else {
-                    self.s.word("..=");
-                }
-                if let Some(ref e) = *end {
-                    self.print_expr_maybe_paren(e, fake_prec);
-                }
-            }
-            ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
-            ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
-            ast::ExprKind::Break(opt_label, ref opt_expr) => {
-                self.s.word("break");
-                self.s.space();
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.s.space();
-                }
-                if let Some(ref expr) = *opt_expr {
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                    self.s.space();
-                }
-            }
-            ast::ExprKind::Continue(opt_label) => {
-                self.s.word("continue");
-                self.s.space();
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.s.space()
-                }
-            }
-            ast::ExprKind::Ret(ref result) => {
-                self.s.word("return");
-                if let Some(ref expr) = *result {
-                    self.s.word(" ");
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::InlineAsm(ref a) => {
-                enum AsmArg<'a> {
-                    Template(String),
-                    Operand(&'a InlineAsmOperand),
-                    Options(InlineAsmOptions),
-                }
-
-                let mut args = vec![];
-                args.push(AsmArg::Template(InlineAsmTemplatePiece::to_string(&a.template)));
-                args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
-                if !a.options.is_empty() {
-                    args.push(AsmArg::Options(a.options));
-                }
-
-                self.word("asm!");
-                self.popen();
-                self.commasep(Consistent, &args, |s, arg| match arg {
-                    AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked),
-                    AsmArg::Operand(op) => {
-                        let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r
-                        {
-                            InlineAsmRegOrRegClass::Reg(r) => {
-                                s.print_symbol(*r, ast::StrStyle::Cooked)
-                            }
-                            InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
-                        };
-                        match op {
-                            InlineAsmOperand::In { reg, expr } => {
-                                s.word("in");
-                                s.popen();
-                                print_reg_or_class(s, reg);
-                                s.pclose();
-                                s.space();
-                                s.print_expr(expr);
-                            }
-                            InlineAsmOperand::Out { reg, late, expr } => {
-                                s.word(if *late { "lateout" } else { "out" });
-                                s.popen();
-                                print_reg_or_class(s, reg);
-                                s.pclose();
-                                s.space();
-                                match expr {
-                                    Some(expr) => s.print_expr(expr),
-                                    None => s.word("_"),
-                                }
-                            }
-                            InlineAsmOperand::InOut { reg, late, expr } => {
-                                s.word(if *late { "inlateout" } else { "inout" });
-                                s.popen();
-                                print_reg_or_class(s, reg);
-                                s.pclose();
-                                s.space();
-                                s.print_expr(expr);
-                            }
-                            InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
-                                s.word(if *late { "inlateout" } else { "inout" });
-                                s.popen();
-                                print_reg_or_class(s, reg);
-                                s.pclose();
-                                s.space();
-                                s.print_expr(in_expr);
-                                s.space();
-                                s.word_space("=>");
-                                match out_expr {
-                                    Some(out_expr) => s.print_expr(out_expr),
-                                    None => s.word("_"),
-                                }
-                            }
-                            InlineAsmOperand::Const { expr } => {
-                                s.word("const");
-                                s.space();
-                                s.print_expr(expr);
-                            }
-                            InlineAsmOperand::Sym { expr } => {
-                                s.word("sym");
-                                s.space();
-                                s.print_expr(expr);
-                            }
-                        }
-                    }
-                    AsmArg::Options(opts) => {
-                        s.word("options");
-                        s.popen();
-                        let mut options = vec![];
-                        if opts.contains(InlineAsmOptions::PURE) {
-                            options.push("pure");
-                        }
-                        if opts.contains(InlineAsmOptions::NOMEM) {
-                            options.push("nomem");
-                        }
-                        if opts.contains(InlineAsmOptions::READONLY) {
-                            options.push("readonly");
-                        }
-                        if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) {
-                            options.push("preserves_flags");
-                        }
-                        if opts.contains(InlineAsmOptions::NORETURN) {
-                            options.push("noreturn");
-                        }
-                        if opts.contains(InlineAsmOptions::NOSTACK) {
-                            options.push("nostack");
-                        }
-                        if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
-                            options.push("att_syntax");
-                        }
-                        s.commasep(Inconsistent, &options, |s, &opt| {
-                            s.word(opt);
-                        });
-                        s.pclose();
-                    }
-                });
-                self.pclose();
-            }
-            ast::ExprKind::LlvmInlineAsm(ref a) => {
-                self.s.word("llvm_asm!");
-                self.popen();
-                self.print_symbol(a.asm, a.asm_str_style);
-                self.word_space(":");
-
-                self.commasep(Inconsistent, &a.outputs, |s, out| {
-                    let constraint = out.constraint.as_str();
-                    let mut ch = constraint.chars();
-                    match ch.next() {
-                        Some('=') if out.is_rw => {
-                            s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
-                        }
-                        _ => s.print_string(&constraint, ast::StrStyle::Cooked),
-                    }
-                    s.popen();
-                    s.print_expr(&out.expr);
-                    s.pclose();
-                });
-                self.s.space();
-                self.word_space(":");
-
-                self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
-                    s.print_symbol(co, ast::StrStyle::Cooked);
-                    s.popen();
-                    s.print_expr(o);
-                    s.pclose();
-                });
-                self.s.space();
-                self.word_space(":");
-
-                self.commasep(Inconsistent, &a.clobbers, |s, &co| {
-                    s.print_symbol(co, ast::StrStyle::Cooked);
-                });
-
-                let mut options = vec![];
-                if a.volatile {
-                    options.push("volatile");
-                }
-                if a.alignstack {
-                    options.push("alignstack");
-                }
-                if a.dialect == ast::LlvmAsmDialect::Intel {
-                    options.push("intel");
-                }
-
-                if !options.is_empty() {
-                    self.s.space();
-                    self.word_space(":");
-                    self.commasep(Inconsistent, &options, |s, &co| {
-                        s.print_string(co, ast::StrStyle::Cooked);
-                    });
-                }
-
-                self.pclose();
-            }
-            ast::ExprKind::MacCall(ref m) => self.print_mac(m),
-            ast::ExprKind::Paren(ref e) => {
-                self.popen();
-                self.print_inner_attributes_inline(attrs);
-                self.print_expr(e);
-                self.pclose();
-            }
-            ast::ExprKind::Yield(ref e) => {
-                self.s.word("yield");
-
-                if let Some(ref expr) = *e {
-                    self.s.space();
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::Try(ref e) => {
-                self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
-                self.s.word("?")
-            }
-            ast::ExprKind::TryBlock(ref blk) => {
-                self.head("try");
-                self.s.space();
-                self.print_block_with_attrs(blk, attrs)
-            }
-            ast::ExprKind::Err => {
-                self.popen();
-                self.s.word("/*ERROR*/");
-                self.pclose()
-            }
-        }
-        self.ann.post(self, AnnNode::Expr(expr));
-        self.end();
-    }
-
-    crate fn print_local_decl(&mut self, loc: &ast::Local) {
-        self.print_pat(&loc.pat);
-        if let Some(ref ty) = loc.ty {
-            self.word_space(":");
-            self.print_type(ty);
-        }
-    }
-
-    pub fn print_usize(&mut self, i: usize) {
-        self.s.word(i.to_string())
-    }
-
-    crate fn print_name(&mut self, name: Symbol) {
-        self.s.word(name.to_string());
-        self.ann.post(self, AnnNode::Name(&name))
-    }
-
-    fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
-        self.s.word("<");
-        self.print_type(&qself.ty);
-        if qself.position > 0 {
-            self.s.space();
-            self.word_space("as");
-            let depth = path.segments.len() - qself.position;
-            self.print_path(path, false, depth);
-        }
-        self.s.word(">");
-        self.s.word("::");
-        let item_segment = path.segments.last().unwrap();
-        self.print_ident(item_segment.ident);
-        if let Some(ref args) = item_segment.args {
-            self.print_generic_args(args, colons_before_params)
-        }
-    }
-
-    crate fn print_pat(&mut self, pat: &ast::Pat) {
-        self.maybe_print_comment(pat.span.lo());
-        self.ann.pre(self, AnnNode::Pat(pat));
-        /* Pat isn't normalized, but the beauty of it
-        is that it doesn't matter */
-        match pat.kind {
-            PatKind::Wild => self.s.word("_"),
-            PatKind::Ident(binding_mode, ident, ref sub) => {
-                match binding_mode {
-                    ast::BindingMode::ByRef(mutbl) => {
-                        self.word_nbsp("ref");
-                        self.print_mutability(mutbl, false);
-                    }
-                    ast::BindingMode::ByValue(ast::Mutability::Not) => {}
-                    ast::BindingMode::ByValue(ast::Mutability::Mut) => {
-                        self.word_nbsp("mut");
-                    }
-                }
-                self.print_ident(ident);
-                if let Some(ref p) = *sub {
-                    self.s.space();
-                    self.s.word_space("@");
-                    self.print_pat(p);
-                }
-            }
-            PatKind::TupleStruct(ref path, ref elts) => {
-                self.print_path(path, true, 0);
-                self.popen();
-                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
-                self.pclose();
-            }
-            PatKind::Or(ref pats) => {
-                self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
-            }
-            PatKind::Path(None, ref path) => {
-                self.print_path(path, true, 0);
-            }
-            PatKind::Path(Some(ref qself), ref path) => {
-                self.print_qpath(path, qself, false);
-            }
-            PatKind::Struct(ref path, ref fields, etc) => {
-                self.print_path(path, true, 0);
-                self.nbsp();
-                self.word_space("{");
-                self.commasep_cmnt(
-                    Consistent,
-                    &fields[..],
-                    |s, f| {
-                        s.cbox(INDENT_UNIT);
-                        if !f.is_shorthand {
-                            s.print_ident(f.ident);
-                            s.word_nbsp(":");
-                        }
-                        s.print_pat(&f.pat);
-                        s.end();
-                    },
-                    |f| f.pat.span,
-                );
-                if etc {
-                    if !fields.is_empty() {
-                        self.word_space(",");
-                    }
-                    self.s.word("..");
-                }
-                self.s.space();
-                self.s.word("}");
-            }
-            PatKind::Tuple(ref elts) => {
-                self.popen();
-                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
-                if elts.len() == 1 {
-                    self.s.word(",");
-                }
-                self.pclose();
-            }
-            PatKind::Box(ref inner) => {
-                self.s.word("box ");
-                self.print_pat(inner);
-            }
-            PatKind::Ref(ref inner, mutbl) => {
-                self.s.word("&");
-                if mutbl == ast::Mutability::Mut {
-                    self.s.word("mut ");
-                }
-                self.print_pat(inner);
-            }
-            PatKind::Lit(ref e) => self.print_expr(&**e),
-            PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
-                if let Some(e) = begin {
-                    self.print_expr(e);
-                    self.s.space();
-                }
-                match *end_kind {
-                    RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."),
-                    RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="),
-                    RangeEnd::Excluded => self.s.word(".."),
-                }
-                if let Some(e) = end {
-                    self.print_expr(e);
-                }
-            }
-            PatKind::Slice(ref elts) => {
-                self.s.word("[");
-                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
-                self.s.word("]");
-            }
-            PatKind::Rest => self.s.word(".."),
-            PatKind::Paren(ref inner) => {
-                self.popen();
-                self.print_pat(inner);
-                self.pclose();
-            }
-            PatKind::MacCall(ref m) => self.print_mac(m),
-        }
-        self.ann.post(self, AnnNode::Pat(pat))
-    }
-
-    fn print_arm(&mut self, arm: &ast::Arm) {
-        // Note, I have no idea why this check is necessary, but here it is.
-        if arm.attrs.is_empty() {
-            self.s.space();
-        }
-        self.cbox(INDENT_UNIT);
-        self.ibox(0);
-        self.maybe_print_comment(arm.pat.span.lo());
-        self.print_outer_attributes(&arm.attrs);
-        self.print_pat(&arm.pat);
-        self.s.space();
-        if let Some(ref e) = arm.guard {
-            self.word_space("if");
-            self.print_expr(e);
-            self.s.space();
-        }
-        self.word_space("=>");
-
-        match arm.body.kind {
-            ast::ExprKind::Block(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-
-                // The block will close the pattern's ibox.
-                self.print_block_unclosed_indent(blk);
-
-                // If it is a user-provided unsafe block, print a comma after it.
-                if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
-                    self.s.word(",");
-                }
-            }
-            _ => {
-                self.end(); // Close the ibox for the pattern.
-                self.print_expr(&arm.body);
-                self.s.word(",");
-            }
-        }
-        self.end(); // Close enclosing cbox.
-    }
-
-    fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
-        match explicit_self.node {
-            SelfKind::Value(m) => {
-                self.print_mutability(m, false);
-                self.s.word("self")
-            }
-            SelfKind::Region(ref lt, m) => {
-                self.s.word("&");
-                self.print_opt_lifetime(lt);
-                self.print_mutability(m, false);
-                self.s.word("self")
-            }
-            SelfKind::Explicit(ref typ, m) => {
-                self.print_mutability(m, false);
-                self.s.word("self");
-                self.word_space(":");
-                self.print_type(typ)
-            }
-        }
-    }
-
-    fn print_fn_full(
-        &mut self,
-        sig: &ast::FnSig,
-        name: Ident,
-        generics: &ast::Generics,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-        body: Option<&ast::Block>,
-        attrs: &[ast::Attribute],
-    ) {
-        if body.is_some() {
-            self.head("");
-        }
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        self.print_fn(&sig.decl, sig.header, Some(name), generics);
-        if let Some(body) = body {
-            self.nbsp();
-            self.print_block_with_attrs(body, attrs);
-        } else {
-            self.s.word(";");
-        }
-    }
-
-    crate fn print_fn(
-        &mut self,
-        decl: &ast::FnDecl,
-        header: ast::FnHeader,
-        name: Option<Ident>,
-        generics: &ast::Generics,
-    ) {
-        self.print_fn_header_info(header);
-        if let Some(name) = name {
-            self.nbsp();
-            self.print_ident(name);
-        }
-        self.print_generic_params(&generics.params);
-        self.print_fn_params_and_ret(decl, false);
-        self.print_where_clause(&generics.where_clause)
-    }
-
-    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
-        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
-        self.word(open);
-        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
-        self.word(close);
-        self.print_fn_ret_ty(&decl.output)
-    }
-
-    crate fn print_movability(&mut self, movability: ast::Movability) {
-        match movability {
-            ast::Movability::Static => self.word_space("static"),
-            ast::Movability::Movable => {}
-        }
-    }
-
-    crate fn print_asyncness(&mut self, asyncness: ast::Async) {
-        if asyncness.is_async() {
-            self.word_nbsp("async");
-        }
-    }
-
-    crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
-        match capture_clause {
-            ast::CaptureBy::Value => self.word_space("move"),
-            ast::CaptureBy::Ref => {}
-        }
-    }
-
-    pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
-        if !bounds.is_empty() {
-            self.s.word(prefix);
-            let mut first = true;
-            for bound in bounds {
-                if !(first && prefix.is_empty()) {
-                    self.nbsp();
-                }
-                if first {
-                    first = false;
-                } else {
-                    self.word_space("+");
-                }
-
-                match bound {
-                    GenericBound::Trait(tref, modifier) => {
-                        if modifier == &TraitBoundModifier::Maybe {
-                            self.s.word("?");
-                        }
-                        self.print_poly_trait_ref(tref);
-                    }
-                    GenericBound::Outlives(lt) => self.print_lifetime(*lt),
-                }
-            }
-        }
-    }
-
-    crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
-        self.print_name(lifetime.ident.name)
-    }
-
-    crate fn print_lifetime_bounds(
-        &mut self,
-        lifetime: ast::Lifetime,
-        bounds: &ast::GenericBounds,
-    ) {
-        self.print_lifetime(lifetime);
-        if !bounds.is_empty() {
-            self.s.word(": ");
-            for (i, bound) in bounds.iter().enumerate() {
-                if i != 0 {
-                    self.s.word(" + ");
-                }
-                match bound {
-                    ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
-                    _ => panic!(),
-                }
-            }
-        }
-    }
-
-    crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
-        if generic_params.is_empty() {
-            return;
-        }
-
-        self.s.word("<");
-
-        self.commasep(Inconsistent, &generic_params, |s, param| {
-            s.print_outer_attributes_inline(&param.attrs);
-
-            match param.kind {
-                ast::GenericParamKind::Lifetime => {
-                    let lt = ast::Lifetime { id: param.id, ident: param.ident };
-                    s.print_lifetime_bounds(lt, &param.bounds)
-                }
-                ast::GenericParamKind::Type { ref default } => {
-                    s.print_ident(param.ident);
-                    s.print_type_bounds(":", &param.bounds);
-                    if let Some(ref default) = default {
-                        s.s.space();
-                        s.word_space("=");
-                        s.print_type(default)
-                    }
-                }
-                ast::GenericParamKind::Const { ref ty, kw_span: _ } => {
-                    s.word_space("const");
-                    s.print_ident(param.ident);
-                    s.s.space();
-                    s.word_space(":");
-                    s.print_type(ty);
-                    s.print_type_bounds(":", &param.bounds)
-                }
-            }
-        });
-
-        self.s.word(">");
-    }
-
-    crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
-        if where_clause.predicates.is_empty() && !where_clause.has_where_token {
-            return;
-        }
-
-        self.s.space();
-        self.word_space("where");
-
-        for (i, predicate) in where_clause.predicates.iter().enumerate() {
-            if i != 0 {
-                self.word_space(",");
-            }
-
-            match *predicate {
-                ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
-                    ref bound_generic_params,
-                    ref bounded_ty,
-                    ref bounds,
-                    ..
-                }) => {
-                    self.print_formal_generic_params(bound_generic_params);
-                    self.print_type(bounded_ty);
-                    self.print_type_bounds(":", bounds);
-                }
-                ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
-                    ref lifetime,
-                    ref bounds,
-                    ..
-                }) => {
-                    self.print_lifetime_bounds(*lifetime, bounds);
-                }
-                ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
-                    ref lhs_ty,
-                    ref rhs_ty,
-                    ..
-                }) => {
-                    self.print_type(lhs_ty);
-                    self.s.space();
-                    self.word_space("=");
-                    self.print_type(rhs_ty);
-                }
-            }
-        }
-    }
-
-    crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
-        match tree.kind {
-            ast::UseTreeKind::Simple(rename, ..) => {
-                self.print_path(&tree.prefix, false, 0);
-                if let Some(rename) = rename {
-                    self.s.space();
-                    self.word_space("as");
-                    self.print_ident(rename);
-                }
-            }
-            ast::UseTreeKind::Glob => {
-                if !tree.prefix.segments.is_empty() {
-                    self.print_path(&tree.prefix, false, 0);
-                    self.s.word("::");
-                }
-                self.s.word("*");
-            }
-            ast::UseTreeKind::Nested(ref items) => {
-                if tree.prefix.segments.is_empty() {
-                    self.s.word("{");
-                } else {
-                    self.print_path(&tree.prefix, false, 0);
-                    self.s.word("::{");
-                }
-                self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| {
-                    this.print_use_tree(tree)
-                });
-                self.s.word("}");
-            }
-        }
-    }
-
-    pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
-        match mutbl {
-            ast::Mutability::Mut => self.word_nbsp("mut"),
-            ast::Mutability::Not => {
-                if print_const {
-                    self.word_nbsp("const");
-                }
-            }
-        }
-    }
-
-    crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
-        self.print_mutability(mt.mutbl, print_const);
-        self.print_type(&mt.ty)
-    }
-
-    crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
-        self.ibox(INDENT_UNIT);
-
-        self.print_outer_attributes_inline(&input.attrs);
-
-        match input.ty.kind {
-            ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
-            _ => {
-                if let Some(eself) = input.to_self() {
-                    self.print_explicit_self(&eself);
-                } else {
-                    let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
-                        ident.name == kw::Invalid
-                    } else {
-                        false
-                    };
-                    if !invalid {
-                        self.print_pat(&input.pat);
-                        self.s.word(":");
-                        self.s.space();
-                    }
-                    self.print_type(&input.ty);
-                }
-            }
-        }
-        self.end();
-    }
-
-    crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
-        if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
-            self.space_if_not_bol();
-            self.ibox(INDENT_UNIT);
-            self.word_space("->");
-            self.print_type(ty);
-            self.end();
-            self.maybe_print_comment(ty.span.lo());
-        }
-    }
-
-    crate fn print_ty_fn(
-        &mut self,
-        ext: ast::Extern,
-        unsafety: ast::Unsafe,
-        decl: &ast::FnDecl,
-        name: Option<Ident>,
-        generic_params: &[ast::GenericParam],
-    ) {
-        self.ibox(INDENT_UNIT);
-        if !generic_params.is_empty() {
-            self.s.word("for");
-            self.print_generic_params(generic_params);
-        }
-        let generics = ast::Generics {
-            params: Vec::new(),
-            where_clause: ast::WhereClause {
-                has_where_token: false,
-                predicates: Vec::new(),
-                span: rustc_span::DUMMY_SP,
-            },
-            span: rustc_span::DUMMY_SP,
-        };
-        let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
-        self.print_fn(decl, header, name, &generics);
-        self.end();
-    }
-
-    crate fn maybe_print_trailing_comment(
-        &mut self,
-        span: rustc_span::Span,
-        next_pos: Option<BytePos>,
-    ) {
-        if let Some(cmnts) = self.comments() {
-            if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
-                self.print_comment(&cmnt);
-            }
-        }
-    }
-
-    crate 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() {
-            self.s.hardbreak();
-        }
-        while let Some(ref cmnt) = self.next_comment() {
-            self.print_comment(cmnt);
-        }
-    }
-
-    crate fn print_fn_header_info(&mut self, header: ast::FnHeader) {
-        self.print_constness(header.constness);
-        self.print_asyncness(header.asyncness);
-        self.print_unsafety(header.unsafety);
-
-        match header.ext {
-            ast::Extern::None => {}
-            ast::Extern::Implicit => {
-                self.word_nbsp("extern");
-            }
-            ast::Extern::Explicit(abi) => {
-                self.word_nbsp("extern");
-                self.print_literal(&abi.as_lit());
-                self.nbsp();
-            }
-        }
-
-        self.s.word("fn")
-    }
-
-    crate fn print_unsafety(&mut self, s: ast::Unsafe) {
-        match s {
-            ast::Unsafe::No => {}
-            ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
-        }
-    }
-
-    crate fn print_constness(&mut self, s: ast::Const) {
-        match s {
-            ast::Const::No => {}
-            ast::Const::Yes(_) => self.word_nbsp("const"),
-        }
-    }
-
-    crate fn print_is_auto(&mut self, s: ast::IsAuto) {
-        match s {
-            ast::IsAuto::Yes => self.word_nbsp("auto"),
-            ast::IsAuto::No => {}
-        }
-    }
-}
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
new file mode 100644
index 0000000..b34ea41
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -0,0 +1,104 @@
+#[cfg(test)]
+mod tests;
+
+pub mod state;
+pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State};
+
+use rustc_ast as ast;
+use rustc_ast::token::{Nonterminal, Token, TokenKind};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+
+pub fn nonterminal_to_string_no_extra_parens(nt: &Nonterminal) -> String {
+    let state = State::without_insert_extra_parens();
+    state.nonterminal_to_string(nt)
+}
+
+pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
+    State::new().nonterminal_to_string(nt)
+}
+
+/// Print the token kind precisely, without converting `$crate` into its respective crate name.
+pub fn token_kind_to_string(tok: &TokenKind) -> String {
+    State::new().token_kind_to_string(tok)
+}
+
+/// Print the token precisely, without converting `$crate` into its respective crate name.
+pub fn token_to_string(token: &Token) -> String {
+    State::new().token_to_string(token)
+}
+
+pub fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
+    State::new().token_to_string_ext(token, convert_dollar_crate)
+}
+
+pub fn ty_to_string(ty: &ast::Ty) -> String {
+    State::new().ty_to_string(ty)
+}
+
+pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
+    State::new().bounds_to_string(bounds)
+}
+
+pub fn pat_to_string(pat: &ast::Pat) -> String {
+    State::new().pat_to_string(pat)
+}
+
+pub fn expr_to_string(e: &ast::Expr) -> String {
+    State::new().expr_to_string(e)
+}
+
+pub fn tt_to_string(tt: &TokenTree) -> String {
+    State::new().tt_to_string(tt)
+}
+
+pub fn tts_to_string(tokens: &TokenStream) -> String {
+    State::new().tts_to_string(tokens)
+}
+
+pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
+    State::new().stmt_to_string(stmt)
+}
+
+pub fn item_to_string(i: &ast::Item) -> String {
+    State::new().item_to_string(i)
+}
+
+pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
+    State::new().generic_params_to_string(generic_params)
+}
+
+pub fn path_to_string(p: &ast::Path) -> String {
+    State::new().path_to_string(p)
+}
+
+pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
+    State::new().path_segment_to_string(p)
+}
+
+pub fn vis_to_string(v: &ast::Visibility) -> String {
+    State::new().vis_to_string(v)
+}
+
+pub fn block_to_string(blk: &ast::Block) -> String {
+    State::new().block_to_string(blk)
+}
+
+pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
+    State::new().meta_list_item_to_string(li)
+}
+
+pub fn attr_item_to_string(ai: &ast::AttrItem) -> String {
+    State::new().attr_item_to_string(ai)
+}
+
+pub fn attribute_to_string(attr: &ast::Attribute) -> String {
+    State::new().attribute_to_string(attr)
+}
+
+pub fn param_to_string(arg: &ast::Param) -> String {
+    State::new().param_to_string(arg)
+}
+
+pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
+    State::new().to_string(f)
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
new file mode 100644
index 0000000..029a6cb
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -0,0 +1,2912 @@
+use crate::pp::Breaks::{Consistent, Inconsistent};
+use crate::pp::{self, Breaks};
+
+use rustc_ast::attr;
+use rustc_ast::ptr::P;
+use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::util::classify;
+use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
+use rustc_ast::util::parser::{self, AssocOp, Fixity};
+use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
+use rustc_ast::{GenericArg, MacArgs};
+use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
+use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_span::edition::Edition;
+use rustc_span::source_map::{SourceMap, Spanned};
+use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
+use rustc_span::{BytePos, FileName, Span};
+
+use std::borrow::Cow;
+
+pub enum MacHeader<'a> {
+    Path(&'a ast::Path),
+    Keyword(&'static str),
+}
+
+pub enum AnnNode<'a> {
+    Ident(&'a Ident),
+    Name(&'a Symbol),
+    Block(&'a ast::Block),
+    Item(&'a ast::Item),
+    SubItem(ast::NodeId),
+    Expr(&'a ast::Expr),
+    Pat(&'a ast::Pat),
+    Crate(&'a ast::Crate),
+}
+
+pub trait PpAnn {
+    fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
+    fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
+}
+
+#[derive(Copy, Clone)]
+pub struct NoAnn;
+
+impl PpAnn for NoAnn {}
+
+pub struct Comments<'a> {
+    sm: &'a SourceMap,
+    comments: Vec<Comment>,
+    current: usize,
+}
+
+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 }
+    }
+
+    pub fn next(&self) -> Option<Comment> {
+        self.comments.get(self.current).cloned()
+    }
+
+    pub fn trailing_comment(
+        &self,
+        span: rustc_span::Span,
+        next_pos: Option<BytePos>,
+    ) -> Option<Comment> {
+        if let Some(cmnt) = self.next() {
+            if cmnt.style != CommentStyle::Trailing {
+                return None;
+            }
+            let span_line = self.sm.lookup_char_pos(span.hi());
+            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);
+            }
+        }
+
+        None
+    }
+}
+
+pub struct State<'a> {
+    pub s: pp::Printer,
+    comments: Option<Comments<'a>>,
+    ann: &'a (dyn PpAnn + 'a),
+    is_expanded: bool,
+    // If `true`, additional parenthesis (separate from `ExprKind::Paren`)
+    // are inserted to ensure that proper precedence is preserved
+    // in the pretty-printed output.
+    //
+    // This is usually `true`, except when performing the pretty-print/reparse
+    // check in `nt_to_tokenstream`
+    insert_extra_parens: bool,
+}
+
+crate const INDENT_UNIT: usize = 4;
+
+/// Requires you to pass an input filename and reader so that
+/// it can scan the input text for comments to copy forward.
+pub fn print_crate<'a>(
+    sm: &'a SourceMap,
+    krate: &ast::Crate,
+    filename: FileName,
+    input: String,
+    ann: &'a dyn PpAnn,
+    is_expanded: bool,
+    edition: Edition,
+    has_injected_crate: bool,
+) -> String {
+    let mut s = State {
+        s: pp::mk_printer(),
+        comments: Some(Comments::new(sm, filename, input)),
+        ann,
+        is_expanded,
+        insert_extra_parens: true,
+    };
+
+    if is_expanded && has_injected_crate {
+        // We need to print `#![no_std]` (and its feature gate) so that
+        // compiling pretty-printed source won't inject libstd again.
+        // However, we don't want these attributes in the AST because
+        // of the feature gate, so we fake them up here.
+
+        // `#![feature(prelude_import)]`
+        let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
+        let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
+        let fake_attr = attr::mk_attr_inner(list);
+        s.print_attribute(&fake_attr);
+
+        // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
+        // root, so this is not needed, and actually breaks things.
+        if edition == Edition::Edition2015 {
+            // `#![no_std]`
+            let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
+            let fake_attr = attr::mk_attr_inner(no_std_meta);
+            s.print_attribute(&fake_attr);
+        }
+    }
+
+    s.print_mod(&krate.module, &krate.attrs);
+    s.print_remaining_comments();
+    s.ann.post(&mut s, AnnNode::Crate(krate));
+    s.s.eof()
+}
+
+// This makes printed token streams look slightly nicer,
+// and also addresses some specific regressions described in #63896 and #73345.
+fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
+    if let TokenTree::Token(token) = prev {
+        if let token::DocComment(comment_kind, ..) = token.kind {
+            return comment_kind != CommentKind::Line;
+        }
+    }
+    match tt {
+        TokenTree::Token(token) => match token.kind {
+            token::Comma => false,
+            _ => true,
+        },
+        TokenTree::Delimited(_, DelimToken::Paren, _) => match prev {
+            TokenTree::Token(token) => match token.kind {
+                token::Ident(_, _) => false,
+                _ => true,
+            },
+            _ => true,
+        },
+        TokenTree::Delimited(_, DelimToken::Bracket, _) => match prev {
+            TokenTree::Token(token) => match token.kind {
+                token::Pound => false,
+                _ => true,
+            },
+            _ => true,
+        },
+        TokenTree::Delimited(..) => true,
+    }
+}
+
+fn binop_to_string(op: BinOpToken) -> &'static str {
+    match op {
+        token::Plus => "+",
+        token::Minus => "-",
+        token::Star => "*",
+        token::Slash => "/",
+        token::Percent => "%",
+        token::Caret => "^",
+        token::And => "&",
+        token::Or => "|",
+        token::Shl => "<<",
+        token::Shr => ">>",
+    }
+}
+
+fn doc_comment_to_string(
+    comment_kind: CommentKind,
+    attr_style: ast::AttrStyle,
+    data: Symbol,
+) -> String {
+    match (comment_kind, attr_style) {
+        (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
+        (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
+        (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
+        (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
+    }
+}
+
+pub fn literal_to_string(lit: token::Lit) -> String {
+    let token::Lit { kind, symbol, suffix } = lit;
+    let mut out = match kind {
+        token::Byte => format!("b'{}'", symbol),
+        token::Char => format!("'{}'", symbol),
+        token::Str => format!("\"{}\"", symbol),
+        token::StrRaw(n) => {
+            format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
+        }
+        token::ByteStr => format!("b\"{}\"", symbol),
+        token::ByteStrRaw(n) => {
+            format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
+        }
+        token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
+    };
+
+    if let Some(suffix) = suffix {
+        out.push_str(&suffix.as_str())
+    }
+
+    out
+}
+
+fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
+    format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s)
+}
+
+impl std::ops::Deref for State<'_> {
+    type Target = pp::Printer;
+    fn deref(&self) -> &Self::Target {
+        &self.s
+    }
+}
+
+impl std::ops::DerefMut for State<'_> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.s
+    }
+}
+
+pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
+    fn insert_extra_parens(&self) -> bool;
+    fn comments(&mut self) -> &mut Option<Comments<'a>>;
+    fn print_ident(&mut self, ident: Ident);
+    fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
+
+    fn strsep<T, F>(
+        &mut self,
+        sep: &'static str,
+        space_before: bool,
+        b: Breaks,
+        elts: &[T],
+        mut op: F,
+    ) where
+        F: FnMut(&mut Self, &T),
+    {
+        self.rbox(0, b);
+        if let Some((first, rest)) = elts.split_first() {
+            op(self, first);
+            for elt in rest {
+                if space_before {
+                    self.space();
+                }
+                self.word_space(sep);
+                op(self, elt);
+            }
+        }
+        self.end();
+    }
+
+    fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
+    where
+        F: FnMut(&mut Self, &T),
+    {
+        self.strsep(",", false, b, elts, op)
+    }
+
+    fn maybe_print_comment(&mut self, pos: BytePos) {
+        while let Some(ref cmnt) = self.next_comment() {
+            if cmnt.pos < pos {
+                self.print_comment(cmnt);
+            } else {
+                break;
+            }
+        }
+    }
+
+    fn print_comment(&mut self, cmnt: &Comment) {
+        match cmnt.style {
+            CommentStyle::Mixed => {
+                if !self.is_beginning_of_line() {
+                    self.zerobreak();
+                }
+                if let Some((last, lines)) = cmnt.lines.split_last() {
+                    self.ibox(0);
+
+                    for line in lines {
+                        self.word(line.clone());
+                        self.hardbreak()
+                    }
+
+                    self.word(last.clone());
+                    self.space();
+
+                    self.end();
+                }
+                self.zerobreak()
+            }
+            CommentStyle::Isolated => {
+                self.hardbreak_if_not_bol();
+                for line in &cmnt.lines {
+                    // Don't print empty lines because they will end up as trailing
+                    // whitespace.
+                    if !line.is_empty() {
+                        self.word(line.clone());
+                    }
+                    self.hardbreak();
+                }
+            }
+            CommentStyle::Trailing => {
+                if !self.is_beginning_of_line() {
+                    self.word(" ");
+                }
+                if cmnt.lines.len() == 1 {
+                    self.word(cmnt.lines[0].clone());
+                    self.hardbreak()
+                } else {
+                    self.ibox(0);
+                    for line in &cmnt.lines {
+                        if !line.is_empty() {
+                            self.word(line.clone());
+                        }
+                        self.hardbreak();
+                    }
+                    self.end();
+                }
+            }
+            CommentStyle::BlankLine => {
+                // We need to do at least one, possibly two hardbreaks.
+                let twice = match self.last_token() {
+                    pp::Token::String(s) => ";" == s,
+                    pp::Token::Begin(_) => true,
+                    pp::Token::End => true,
+                    _ => false,
+                };
+                if twice {
+                    self.hardbreak();
+                }
+                self.hardbreak();
+            }
+        }
+        if let Some(cmnts) = self.comments() {
+            cmnts.current += 1;
+        }
+    }
+
+    fn next_comment(&mut self) -> Option<Comment> {
+        self.comments().as_mut().and_then(|c| c.next())
+    }
+
+    fn print_literal(&mut self, lit: &ast::Lit) {
+        self.maybe_print_comment(lit.span.lo());
+        self.word(lit.token.to_string())
+    }
+
+    fn print_string(&mut self, st: &str, style: ast::StrStyle) {
+        let st = match style {
+            ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
+            ast::StrStyle::Raw(n) => {
+                format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
+            }
+        };
+        self.word(st)
+    }
+
+    fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
+        self.print_string(&sym.as_str(), style);
+    }
+
+    fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
+        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
+    }
+
+    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
+        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
+    }
+
+    fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
+        self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
+    }
+
+    fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+        self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
+    }
+
+    fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+        self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
+    }
+
+    fn print_either_attributes(
+        &mut self,
+        attrs: &[ast::Attribute],
+        kind: ast::AttrStyle,
+        is_inline: bool,
+        trailing_hardbreak: bool,
+    ) {
+        let mut count = 0;
+        for attr in attrs {
+            if attr.style == kind {
+                self.print_attribute_inline(attr, is_inline);
+                if is_inline {
+                    self.nbsp();
+                }
+                count += 1;
+            }
+        }
+        if count > 0 && trailing_hardbreak && !is_inline {
+            self.hardbreak_if_not_bol();
+        }
+    }
+
+    fn print_attribute(&mut self, attr: &ast::Attribute) {
+        self.print_attribute_inline(attr, false)
+    }
+
+    fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
+        if !is_inline {
+            self.hardbreak_if_not_bol();
+        }
+        self.maybe_print_comment(attr.span.lo());
+        match attr.kind {
+            ast::AttrKind::Normal(ref item) => {
+                match attr.style {
+                    ast::AttrStyle::Inner => self.word("#!["),
+                    ast::AttrStyle::Outer => self.word("#["),
+                }
+                self.print_attr_item(&item, attr.span);
+                self.word("]");
+            }
+            ast::AttrKind::DocComment(comment_kind, data) => {
+                self.word(doc_comment_to_string(comment_kind, attr.style, data));
+                self.hardbreak()
+            }
+        }
+    }
+
+    fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
+        self.ibox(0);
+        match &item.args {
+            MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
+                Some(MacHeader::Path(&item.path)),
+                false,
+                None,
+                delim.to_token(),
+                tokens,
+                true,
+                span,
+            ),
+            MacArgs::Empty | MacArgs::Eq(..) => {
+                self.print_path(&item.path, false, 0);
+                if let MacArgs::Eq(_, tokens) = &item.args {
+                    self.space();
+                    self.word_space("=");
+                    self.print_tts(tokens, true);
+                }
+            }
+        }
+        self.end();
+    }
+
+    fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
+        match item {
+            ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
+            ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
+        }
+    }
+
+    fn print_meta_item(&mut self, item: &ast::MetaItem) {
+        self.ibox(INDENT_UNIT);
+        match item.kind {
+            ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
+            ast::MetaItemKind::NameValue(ref value) => {
+                self.print_path(&item.path, false, 0);
+                self.space();
+                self.word_space("=");
+                self.print_literal(value);
+            }
+            ast::MetaItemKind::List(ref items) => {
+                self.print_path(&item.path, false, 0);
+                self.popen();
+                self.commasep(Consistent, &items[..], |s, i| s.print_meta_list_item(i));
+                self.pclose();
+            }
+        }
+        self.end();
+    }
+
+    /// This doesn't deserve to be called "pretty" printing, but it should be
+    /// meaning-preserving. A quick hack that might help would be to look at the
+    /// spans embedded in the TTs to decide where to put spaces and newlines.
+    /// But it'd be better to parse these according to the grammar of the
+    /// appropriate macro, transcribe back into the grammar we just parsed from,
+    /// and then pretty-print the resulting AST nodes (so, e.g., we print
+    /// expression arguments as expressions). It can be done! I think.
+    fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
+        match tt {
+            TokenTree::Token(token) => {
+                let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
+                self.word(token_str);
+                if let token::DocComment(..) = token.kind {
+                    self.hardbreak()
+                }
+            }
+            TokenTree::Delimited(dspan, delim, tts) => {
+                self.print_mac_common(
+                    None,
+                    false,
+                    None,
+                    *delim,
+                    tts,
+                    convert_dollar_crate,
+                    dspan.entire(),
+                );
+            }
+        }
+    }
+
+    fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
+        let mut iter = tts.trees().peekable();
+        while let Some(tt) = iter.next() {
+            self.print_tt(&tt, convert_dollar_crate);
+            if let Some(next) = iter.peek() {
+                if tt_prepend_space(next, &tt) {
+                    self.space();
+                }
+            }
+        }
+    }
+
+    fn print_mac_common(
+        &mut self,
+        header: Option<MacHeader<'_>>,
+        has_bang: bool,
+        ident: Option<Ident>,
+        delim: DelimToken,
+        tts: &TokenStream,
+        convert_dollar_crate: bool,
+        span: Span,
+    ) {
+        if delim == DelimToken::Brace {
+            self.cbox(INDENT_UNIT);
+        }
+        match header {
+            Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
+            Some(MacHeader::Keyword(kw)) => self.word(kw),
+            None => {}
+        }
+        if has_bang {
+            self.word("!");
+        }
+        if let Some(ident) = ident {
+            self.nbsp();
+            self.print_ident(ident);
+        }
+        match delim {
+            DelimToken::Brace => {
+                if header.is_some() || has_bang || ident.is_some() {
+                    self.nbsp();
+                }
+                self.word("{");
+                if !tts.is_empty() {
+                    self.space();
+                }
+            }
+            _ => {
+                let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
+                self.word(token_str)
+            }
+        }
+        self.ibox(0);
+        self.print_tts(tts, convert_dollar_crate);
+        self.end();
+        match delim {
+            DelimToken::Brace => self.bclose(span),
+            _ => {
+                let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
+                self.word(token_str)
+            }
+        }
+    }
+
+    fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
+        self.maybe_print_comment(path.span.lo());
+
+        for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
+            if i > 0 {
+                self.word("::")
+            }
+            self.print_path_segment(segment, colons_before_params);
+        }
+    }
+
+    fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
+        if segment.ident.name != kw::PathRoot {
+            self.print_ident(segment.ident);
+            if let Some(ref args) = segment.args {
+                self.print_generic_args(args, colons_before_params);
+            }
+        }
+    }
+
+    fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
+        let w = w.into();
+        // Outer-box is consistent.
+        self.cbox(INDENT_UNIT);
+        // Head-box is inconsistent.
+        self.ibox(w.len() + 1);
+        // Keyword that starts the head.
+        if !w.is_empty() {
+            self.word_nbsp(w);
+        }
+    }
+
+    fn bopen(&mut self) {
+        self.word("{");
+        self.end(); // Close the head-box.
+    }
+
+    fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
+        self.maybe_print_comment(span.hi());
+        self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
+        self.word("}");
+        if close_box {
+            self.end(); // Close the outer-box.
+        }
+    }
+
+    fn bclose(&mut self, span: rustc_span::Span) {
+        self.bclose_maybe_open(span, true)
+    }
+
+    fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
+        if !self.is_beginning_of_line() {
+            self.break_offset(n, off)
+        } else {
+            if off != 0 && self.last_token().is_hardbreak_tok() {
+                // We do something pretty sketchy here: tuck the nonzero
+                // offset-adjustment we were going to deposit along with the
+                // break into the previous hardbreak.
+                self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
+            }
+        }
+    }
+
+    fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
+        match *nt {
+            token::NtExpr(ref e) => self.expr_to_string(e),
+            token::NtMeta(ref e) => self.attr_item_to_string(e),
+            token::NtTy(ref e) => self.ty_to_string(e),
+            token::NtPath(ref e) => self.path_to_string(e),
+            token::NtItem(ref e) => self.item_to_string(e),
+            token::NtBlock(ref e) => self.block_to_string(e),
+            token::NtStmt(ref e) => self.stmt_to_string(e),
+            token::NtPat(ref e) => self.pat_to_string(e),
+            token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
+            token::NtLifetime(e) => e.to_string(),
+            token::NtLiteral(ref e) => self.expr_to_string(e),
+            token::NtTT(ref tree) => self.tt_to_string(tree),
+            token::NtVis(ref e) => self.vis_to_string(e),
+        }
+    }
+
+    /// Print the token kind precisely, without converting `$crate` into its respective crate name.
+    fn token_kind_to_string(&self, tok: &TokenKind) -> String {
+        self.token_kind_to_string_ext(tok, None)
+    }
+
+    fn token_kind_to_string_ext(
+        &self,
+        tok: &TokenKind,
+        convert_dollar_crate: Option<Span>,
+    ) -> String {
+        match *tok {
+            token::Eq => "=".to_string(),
+            token::Lt => "<".to_string(),
+            token::Le => "<=".to_string(),
+            token::EqEq => "==".to_string(),
+            token::Ne => "!=".to_string(),
+            token::Ge => ">=".to_string(),
+            token::Gt => ">".to_string(),
+            token::Not => "!".to_string(),
+            token::Tilde => "~".to_string(),
+            token::OrOr => "||".to_string(),
+            token::AndAnd => "&&".to_string(),
+            token::BinOp(op) => binop_to_string(op).to_string(),
+            token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
+
+            /* Structural symbols */
+            token::At => "@".to_string(),
+            token::Dot => ".".to_string(),
+            token::DotDot => "..".to_string(),
+            token::DotDotDot => "...".to_string(),
+            token::DotDotEq => "..=".to_string(),
+            token::Comma => ",".to_string(),
+            token::Semi => ";".to_string(),
+            token::Colon => ":".to_string(),
+            token::ModSep => "::".to_string(),
+            token::RArrow => "->".to_string(),
+            token::LArrow => "<-".to_string(),
+            token::FatArrow => "=>".to_string(),
+            token::OpenDelim(token::Paren) => "(".to_string(),
+            token::CloseDelim(token::Paren) => ")".to_string(),
+            token::OpenDelim(token::Bracket) => "[".to_string(),
+            token::CloseDelim(token::Bracket) => "]".to_string(),
+            token::OpenDelim(token::Brace) => "{".to_string(),
+            token::CloseDelim(token::Brace) => "}".to_string(),
+            token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(),
+            token::Pound => "#".to_string(),
+            token::Dollar => "$".to_string(),
+            token::Question => "?".to_string(),
+            token::SingleQuote => "'".to_string(),
+
+            /* Literals */
+            token::Literal(lit) => literal_to_string(lit),
+
+            /* Name components */
+            token::Ident(s, is_raw) => {
+                IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string()
+            }
+            token::Lifetime(s) => s.to_string(),
+
+            /* Other */
+            token::DocComment(comment_kind, attr_style, data) => {
+                doc_comment_to_string(comment_kind, attr_style, data)
+            }
+            token::Eof => "<eof>".to_string(),
+
+            token::Interpolated(ref nt) => self.nonterminal_to_string(nt),
+        }
+    }
+
+    /// Print the token precisely, without converting `$crate` into its respective crate name.
+    fn token_to_string(&self, token: &Token) -> String {
+        self.token_to_string_ext(token, false)
+    }
+
+    fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> String {
+        let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
+        self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
+    }
+
+    fn ty_to_string(&self, ty: &ast::Ty) -> String {
+        self.to_string(|s| s.print_type(ty))
+    }
+
+    fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
+        self.to_string(|s| s.print_type_bounds("", bounds))
+    }
+
+    fn pat_to_string(&self, pat: &ast::Pat) -> String {
+        self.to_string(|s| s.print_pat(pat))
+    }
+
+    fn expr_to_string(&self, e: &ast::Expr) -> String {
+        self.to_string(|s| s.print_expr(e))
+    }
+
+    fn tt_to_string(&self, tt: &TokenTree) -> String {
+        self.to_string(|s| s.print_tt(tt, false))
+    }
+
+    fn tts_to_string(&self, tokens: &TokenStream) -> String {
+        self.to_string(|s| s.print_tts(tokens, false))
+    }
+
+    fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
+        self.to_string(|s| s.print_stmt(stmt))
+    }
+
+    fn item_to_string(&self, i: &ast::Item) -> String {
+        self.to_string(|s| s.print_item(i))
+    }
+
+    fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
+        self.to_string(|s| s.print_generic_params(generic_params))
+    }
+
+    fn path_to_string(&self, p: &ast::Path) -> String {
+        self.to_string(|s| s.print_path(p, false, 0))
+    }
+
+    fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
+        self.to_string(|s| s.print_path_segment(p, false))
+    }
+
+    fn vis_to_string(&self, v: &ast::Visibility) -> String {
+        self.to_string(|s| s.print_visibility(v))
+    }
+
+    fn block_to_string(&self, blk: &ast::Block) -> String {
+        self.to_string(|s| {
+            // Containing cbox, will be closed by `print_block` at `}`.
+            s.cbox(INDENT_UNIT);
+            // Head-ibox, will be closed by `print_block` after `{`.
+            s.ibox(0);
+            s.print_block(blk)
+        })
+    }
+
+    fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
+        self.to_string(|s| s.print_meta_list_item(li))
+    }
+
+    fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
+        self.to_string(|s| s.print_attr_item(ai, ai.path.span))
+    }
+
+    fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
+        self.to_string(|s| s.print_attribute(attr))
+    }
+
+    fn param_to_string(&self, arg: &ast::Param) -> String {
+        self.to_string(|s| s.print_param(arg, false))
+    }
+
+    fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
+        let mut printer = State::new();
+        printer.insert_extra_parens = self.insert_extra_parens();
+        f(&mut printer);
+        printer.s.eof()
+    }
+}
+
+impl<'a> PrintState<'a> for State<'a> {
+    fn insert_extra_parens(&self) -> bool {
+        self.insert_extra_parens
+    }
+    fn comments(&mut self) -> &mut Option<Comments<'a>> {
+        &mut self.comments
+    }
+
+    fn print_ident(&mut self, ident: Ident) {
+        self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
+        self.ann.post(self, AnnNode::Ident(&ident))
+    }
+
+    fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
+        if colons_before_params {
+            self.s.word("::")
+        }
+
+        match *args {
+            ast::GenericArgs::AngleBracketed(ref data) => {
+                self.s.word("<");
+                self.commasep(Inconsistent, &data.args, |s, arg| match arg {
+                    ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
+                    ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
+                });
+                self.s.word(">")
+            }
+
+            ast::GenericArgs::Parenthesized(ref data) => {
+                self.s.word("(");
+                self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
+                self.s.word(")");
+                self.print_fn_ret_ty(&data.output);
+            }
+        }
+    }
+}
+
+impl<'a> State<'a> {
+    pub fn new() -> State<'a> {
+        State {
+            s: pp::mk_printer(),
+            comments: None,
+            ann: &NoAnn,
+            is_expanded: false,
+            insert_extra_parens: true,
+        }
+    }
+
+    pub(super) fn without_insert_extra_parens() -> State<'a> {
+        State { insert_extra_parens: false, ..State::new() }
+    }
+
+    // Synthesizes a comment that was not textually present in the original source
+    // file.
+    pub fn synth_comment(&mut self, text: String) {
+        self.s.word("/*");
+        self.s.space();
+        self.s.word(text);
+        self.s.space();
+        self.s.word("*/")
+    }
+
+    crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
+    where
+        F: FnMut(&mut State<'_>, &T),
+        G: FnMut(&T) -> rustc_span::Span,
+    {
+        self.rbox(0, b);
+        let len = elts.len();
+        let mut i = 0;
+        for elt in elts {
+            self.maybe_print_comment(get_span(elt).hi());
+            op(self, elt);
+            i += 1;
+            if i < len {
+                self.s.word(",");
+                self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
+                self.space_if_not_bol();
+            }
+        }
+        self.end();
+    }
+
+    crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
+        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
+    }
+
+    pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) {
+        self.print_inner_attributes(attrs);
+        for item in &_mod.items {
+            self.print_item(item);
+        }
+    }
+
+    crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
+        self.print_inner_attributes(attrs);
+        for item in &nmod.items {
+            self.print_foreign_item(item);
+        }
+    }
+
+    pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
+        if let Some(lt) = *lifetime {
+            self.print_lifetime(lt);
+            self.nbsp();
+        }
+    }
+
+    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
+        self.print_ident(constraint.ident);
+        self.s.space();
+        match &constraint.kind {
+            ast::AssocTyConstraintKind::Equality { ty } => {
+                self.word_space("=");
+                self.print_type(ty);
+            }
+            ast::AssocTyConstraintKind::Bound { bounds } => {
+                self.print_type_bounds(":", &*bounds);
+            }
+        }
+    }
+
+    pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
+        match generic_arg {
+            GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
+            GenericArg::Type(ty) => self.print_type(ty),
+            GenericArg::Const(ct) => self.print_expr(&ct.value),
+        }
+    }
+
+    pub fn print_type(&mut self, ty: &ast::Ty) {
+        self.maybe_print_comment(ty.span.lo());
+        self.ibox(0);
+        match ty.kind {
+            ast::TyKind::Slice(ref ty) => {
+                self.s.word("[");
+                self.print_type(ty);
+                self.s.word("]");
+            }
+            ast::TyKind::Ptr(ref mt) => {
+                self.s.word("*");
+                self.print_mt(mt, true);
+            }
+            ast::TyKind::Rptr(ref lifetime, ref mt) => {
+                self.s.word("&");
+                self.print_opt_lifetime(lifetime);
+                self.print_mt(mt, false);
+            }
+            ast::TyKind::Never => {
+                self.s.word("!");
+            }
+            ast::TyKind::Tup(ref elts) => {
+                self.popen();
+                self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(ty));
+                if elts.len() == 1 {
+                    self.s.word(",");
+                }
+                self.pclose();
+            }
+            ast::TyKind::Paren(ref typ) => {
+                self.popen();
+                self.print_type(typ);
+                self.pclose();
+            }
+            ast::TyKind::BareFn(ref f) => {
+                self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
+            }
+            ast::TyKind::Path(None, ref path) => {
+                self.print_path(path, false, 0);
+            }
+            ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
+            ast::TyKind::TraitObject(ref bounds, syntax) => {
+                let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
+                self.print_type_bounds(prefix, &bounds[..]);
+            }
+            ast::TyKind::ImplTrait(_, ref bounds) => {
+                self.print_type_bounds("impl", &bounds[..]);
+            }
+            ast::TyKind::Array(ref ty, ref length) => {
+                self.s.word("[");
+                self.print_type(ty);
+                self.s.word("; ");
+                self.print_expr(&length.value);
+                self.s.word("]");
+            }
+            ast::TyKind::Typeof(ref e) => {
+                self.s.word("typeof(");
+                self.print_expr(&e.value);
+                self.s.word(")");
+            }
+            ast::TyKind::Infer => {
+                self.s.word("_");
+            }
+            ast::TyKind::Err => {
+                self.popen();
+                self.s.word("/*ERROR*/");
+                self.pclose();
+            }
+            ast::TyKind::ImplicitSelf => {
+                self.s.word("Self");
+            }
+            ast::TyKind::MacCall(ref m) => {
+                self.print_mac(m);
+            }
+            ast::TyKind::CVarArgs => {
+                self.s.word("...");
+            }
+        }
+        self.end();
+    }
+
+    crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+        self.ann.pre(self, AnnNode::SubItem(id));
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(span.lo());
+        self.print_outer_attributes(attrs);
+        match kind {
+            ast::ForeignItemKind::Fn(def, sig, gen, body) => {
+                self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+            }
+            ast::ForeignItemKind::Static(ty, mutbl, body) => {
+                let def = ast::Defaultness::Final;
+                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
+            }
+            ast::ForeignItemKind::TyAlias(def, generics, bounds, ty) => {
+                self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
+            }
+            ast::ForeignItemKind::MacCall(m) => {
+                self.print_mac(m);
+                if m.args.need_semicolon() {
+                    self.s.word(";");
+                }
+            }
+        }
+        self.ann.post(self, AnnNode::SubItem(id))
+    }
+
+    fn print_item_const(
+        &mut self,
+        ident: Ident,
+        mutbl: Option<ast::Mutability>,
+        ty: &ast::Ty,
+        body: Option<&ast::Expr>,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+    ) {
+        self.head("");
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        let leading = match mutbl {
+            None => "const",
+            Some(ast::Mutability::Not) => "static",
+            Some(ast::Mutability::Mut) => "static mut",
+        };
+        self.word_space(leading);
+        self.print_ident(ident);
+        self.word_space(":");
+        self.print_type(ty);
+        self.s.space();
+        self.end(); // end the head-ibox
+        if let Some(body) = body {
+            self.word_space("=");
+            self.print_expr(body);
+        }
+        self.s.word(";");
+        self.end(); // end the outer cbox
+    }
+
+    fn print_associated_type(
+        &mut self,
+        ident: Ident,
+        generics: &ast::Generics,
+        bounds: &ast::GenericBounds,
+        ty: Option<&ast::Ty>,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+    ) {
+        self.head("");
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        self.word_space("type");
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        self.print_type_bounds(":", bounds);
+        self.print_where_clause(&generics.where_clause);
+        if let Some(ty) = ty {
+            self.s.space();
+            self.word_space("=");
+            self.print_type(ty);
+        }
+        self.s.word(";");
+        self.end(); // end inner head-block
+        self.end(); // end outer head-block
+    }
+
+    /// Pretty-prints an item.
+    crate fn print_item(&mut self, item: &ast::Item) {
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(item.span.lo());
+        self.print_outer_attributes(&item.attrs);
+        self.ann.pre(self, AnnNode::Item(item));
+        match item.kind {
+            ast::ItemKind::ExternCrate(orig_name) => {
+                self.head(visibility_qualified(&item.vis, "extern crate"));
+                if let Some(orig_name) = orig_name {
+                    self.print_name(orig_name);
+                    self.s.space();
+                    self.s.word("as");
+                    self.s.space();
+                }
+                self.print_ident(item.ident);
+                self.s.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::Use(ref tree) => {
+                self.head(visibility_qualified(&item.vis, "use"));
+                self.print_use_tree(tree);
+                self.s.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::Static(ref ty, mutbl, ref body) => {
+                let def = ast::Defaultness::Final;
+                self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
+            }
+            ast::ItemKind::Const(def, ref ty, ref body) => {
+                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
+            }
+            ast::ItemKind::Fn(def, ref sig, ref gen, ref body) => {
+                let body = body.as_deref();
+                self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
+            }
+            ast::ItemKind::Mod(ref _mod) => {
+                self.head(self.to_string(|s| {
+                    s.print_visibility(&item.vis);
+                    s.print_unsafety(_mod.unsafety);
+                    s.word("mod");
+                }));
+                self.print_ident(item.ident);
+
+                if _mod.inline || self.is_expanded {
+                    self.nbsp();
+                    self.bopen();
+                    self.print_mod(_mod, &item.attrs);
+                    self.bclose(item.span);
+                } else {
+                    self.s.word(";");
+                    self.end(); // end inner head-block
+                    self.end(); // end outer head-block
+                }
+            }
+            ast::ItemKind::ForeignMod(ref nmod) => {
+                self.head(self.to_string(|s| {
+                    s.print_unsafety(nmod.unsafety);
+                    s.word("extern");
+                }));
+                if let Some(abi) = nmod.abi {
+                    self.print_literal(&abi.as_lit());
+                    self.nbsp();
+                }
+                self.bopen();
+                self.print_foreign_mod(nmod, &item.attrs);
+                self.bclose(item.span);
+            }
+            ast::ItemKind::GlobalAsm(ref ga) => {
+                self.head(visibility_qualified(&item.vis, "global_asm!"));
+                self.s.word(ga.asm.to_string());
+                self.end();
+            }
+            ast::ItemKind::TyAlias(def, ref generics, ref bounds, ref ty) => {
+                let ty = ty.as_deref();
+                self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
+            }
+            ast::ItemKind::Enum(ref enum_definition, ref params) => {
+                self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
+            }
+            ast::ItemKind::Struct(ref struct_def, ref generics) => {
+                self.head(visibility_qualified(&item.vis, "struct"));
+                self.print_struct(struct_def, generics, item.ident, item.span, true);
+            }
+            ast::ItemKind::Union(ref struct_def, ref generics) => {
+                self.head(visibility_qualified(&item.vis, "union"));
+                self.print_struct(struct_def, generics, item.ident, item.span, true);
+            }
+            ast::ItemKind::Impl {
+                unsafety,
+                polarity,
+                defaultness,
+                constness,
+                ref generics,
+                ref of_trait,
+                ref self_ty,
+                ref items,
+            } => {
+                self.head("");
+                self.print_visibility(&item.vis);
+                self.print_defaultness(defaultness);
+                self.print_unsafety(unsafety);
+                self.word_nbsp("impl");
+                self.print_constness(constness);
+
+                if !generics.params.is_empty() {
+                    self.print_generic_params(&generics.params);
+                    self.s.space();
+                }
+
+                if let ast::ImplPolarity::Negative(_) = polarity {
+                    self.s.word("!");
+                }
+
+                if let Some(ref t) = *of_trait {
+                    self.print_trait_ref(t);
+                    self.s.space();
+                    self.word_space("for");
+                }
+
+                self.print_type(self_ty);
+                self.print_where_clause(&generics.where_clause);
+
+                self.s.space();
+                self.bopen();
+                self.print_inner_attributes(&item.attrs);
+                for impl_item in items {
+                    self.print_assoc_item(impl_item);
+                }
+                self.bclose(item.span);
+            }
+            ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
+                self.head("");
+                self.print_visibility(&item.vis);
+                self.print_unsafety(unsafety);
+                self.print_is_auto(is_auto);
+                self.word_nbsp("trait");
+                self.print_ident(item.ident);
+                self.print_generic_params(&generics.params);
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                for b in bounds.iter() {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                        self.s.space();
+                        self.word_space("for ?");
+                        self.print_trait_ref(&ptr.trait_ref);
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.print_type_bounds(":", &real_bounds[..]);
+                self.print_where_clause(&generics.where_clause);
+                self.s.word(" ");
+                self.bopen();
+                self.print_inner_attributes(&item.attrs);
+                for trait_item in trait_items {
+                    self.print_assoc_item(trait_item);
+                }
+                self.bclose(item.span);
+            }
+            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+                self.head("");
+                self.print_visibility(&item.vis);
+                self.word_nbsp("trait");
+                self.print_ident(item.ident);
+                self.print_generic_params(&generics.params);
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                // FIXME(durka) this seems to be some quite outdated syntax
+                for b in bounds.iter() {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                        self.s.space();
+                        self.word_space("for ?");
+                        self.print_trait_ref(&ptr.trait_ref);
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.nbsp();
+                self.print_type_bounds("=", &real_bounds[..]);
+                self.print_where_clause(&generics.where_clause);
+                self.s.word(";");
+            }
+            ast::ItemKind::MacCall(ref mac) => {
+                self.print_mac(mac);
+                if mac.args.need_semicolon() {
+                    self.s.word(";");
+                }
+            }
+            ast::ItemKind::MacroDef(ref macro_def) => {
+                let (kw, has_bang) = if macro_def.macro_rules {
+                    ("macro_rules", true)
+                } else {
+                    self.print_visibility(&item.vis);
+                    ("macro", false)
+                };
+                self.print_mac_common(
+                    Some(MacHeader::Keyword(kw)),
+                    has_bang,
+                    Some(item.ident),
+                    macro_def.body.delim(),
+                    &macro_def.body.inner_tokens(),
+                    true,
+                    item.span,
+                );
+            }
+        }
+        self.ann.post(self, AnnNode::Item(item))
+    }
+
+    fn print_trait_ref(&mut self, t: &ast::TraitRef) {
+        self.print_path(&t.path, false, 0)
+    }
+
+    fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
+        if !generic_params.is_empty() {
+            self.s.word("for");
+            self.print_generic_params(generic_params);
+            self.nbsp();
+        }
+    }
+
+    fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
+        self.print_formal_generic_params(&t.bound_generic_params);
+        self.print_trait_ref(&t.trait_ref)
+    }
+
+    crate fn print_enum_def(
+        &mut self,
+        enum_definition: &ast::EnumDef,
+        generics: &ast::Generics,
+        ident: Ident,
+        span: rustc_span::Span,
+        visibility: &ast::Visibility,
+    ) {
+        self.head(visibility_qualified(visibility, "enum"));
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        self.print_where_clause(&generics.where_clause);
+        self.s.space();
+        self.print_variants(&enum_definition.variants, span)
+    }
+
+    crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
+        self.bopen();
+        for v in variants {
+            self.space_if_not_bol();
+            self.maybe_print_comment(v.span.lo());
+            self.print_outer_attributes(&v.attrs);
+            self.ibox(INDENT_UNIT);
+            self.print_variant(v);
+            self.s.word(",");
+            self.end();
+            self.maybe_print_trailing_comment(v.span, None);
+        }
+        self.bclose(span)
+    }
+
+    crate fn print_visibility(&mut self, vis: &ast::Visibility) {
+        match vis.kind {
+            ast::VisibilityKind::Public => self.word_nbsp("pub"),
+            ast::VisibilityKind::Crate(sugar) => match sugar {
+                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
+                ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
+            },
+            ast::VisibilityKind::Restricted { ref path, .. } => {
+                let path = self.to_string(|s| s.print_path(path, false, 0));
+                if path == "self" || path == "super" {
+                    self.word_nbsp(format!("pub({})", path))
+                } else {
+                    self.word_nbsp(format!("pub(in {})", path))
+                }
+            }
+            ast::VisibilityKind::Inherited => {}
+        }
+    }
+
+    crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
+        if let ast::Defaultness::Default(_) = defaultness {
+            self.word_nbsp("default");
+        }
+    }
+
+    crate fn print_struct(
+        &mut self,
+        struct_def: &ast::VariantData,
+        generics: &ast::Generics,
+        ident: Ident,
+        span: rustc_span::Span,
+        print_finalizer: bool,
+    ) {
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        match struct_def {
+            ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+                if let ast::VariantData::Tuple(..) = struct_def {
+                    self.popen();
+                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
+                        s.maybe_print_comment(field.span.lo());
+                        s.print_outer_attributes(&field.attrs);
+                        s.print_visibility(&field.vis);
+                        s.print_type(&field.ty)
+                    });
+                    self.pclose();
+                }
+                self.print_where_clause(&generics.where_clause);
+                if print_finalizer {
+                    self.s.word(";");
+                }
+                self.end();
+                self.end(); // Close the outer-box.
+            }
+            ast::VariantData::Struct(..) => {
+                self.print_where_clause(&generics.where_clause);
+                self.nbsp();
+                self.bopen();
+                self.hardbreak_if_not_bol();
+
+                for field in struct_def.fields() {
+                    self.hardbreak_if_not_bol();
+                    self.maybe_print_comment(field.span.lo());
+                    self.print_outer_attributes(&field.attrs);
+                    self.print_visibility(&field.vis);
+                    self.print_ident(field.ident.unwrap());
+                    self.word_nbsp(":");
+                    self.print_type(&field.ty);
+                    self.s.word(",");
+                }
+
+                self.bclose(span)
+            }
+        }
+    }
+
+    crate fn print_variant(&mut self, v: &ast::Variant) {
+        self.head("");
+        self.print_visibility(&v.vis);
+        let generics = ast::Generics::default();
+        self.print_struct(&v.data, &generics, v.ident, v.span, false);
+        if let Some(ref d) = v.disr_expr {
+            self.s.space();
+            self.word_space("=");
+            self.print_expr(&d.value)
+        }
+    }
+
+    crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+        self.ann.pre(self, AnnNode::SubItem(id));
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(span.lo());
+        self.print_outer_attributes(attrs);
+        match kind {
+            ast::AssocItemKind::Fn(def, sig, gen, body) => {
+                self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+            }
+            ast::AssocItemKind::Const(def, ty, body) => {
+                self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
+            }
+            ast::AssocItemKind::TyAlias(def, generics, bounds, ty) => {
+                self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
+            }
+            ast::AssocItemKind::MacCall(m) => {
+                self.print_mac(m);
+                if m.args.need_semicolon() {
+                    self.s.word(";");
+                }
+            }
+        }
+        self.ann.post(self, AnnNode::SubItem(id))
+    }
+
+    crate fn print_stmt(&mut self, st: &ast::Stmt) {
+        self.maybe_print_comment(st.span.lo());
+        match st.kind {
+            ast::StmtKind::Local(ref loc) => {
+                self.print_outer_attributes(&loc.attrs);
+                self.space_if_not_bol();
+                self.ibox(INDENT_UNIT);
+                self.word_nbsp("let");
+
+                self.ibox(INDENT_UNIT);
+                self.print_local_decl(loc);
+                self.end();
+                if let Some(ref init) = loc.init {
+                    self.nbsp();
+                    self.word_space("=");
+                    self.print_expr(init);
+                }
+                self.s.word(";");
+                self.end();
+            }
+            ast::StmtKind::Item(ref item) => self.print_item(item),
+            ast::StmtKind::Expr(ref expr) => {
+                self.space_if_not_bol();
+                self.print_expr_outer_attr_style(expr, false);
+                if classify::expr_requires_semi_to_be_stmt(expr) {
+                    self.s.word(";");
+                }
+            }
+            ast::StmtKind::Semi(ref expr) => {
+                self.space_if_not_bol();
+                self.print_expr_outer_attr_style(expr, false);
+                self.s.word(";");
+            }
+            ast::StmtKind::Empty => {
+                self.space_if_not_bol();
+                self.s.word(";");
+            }
+            ast::StmtKind::MacCall(ref mac) => {
+                self.space_if_not_bol();
+                self.print_outer_attributes(&mac.attrs);
+                self.print_mac(&mac.mac);
+                if mac.style == ast::MacStmtStyle::Semicolon {
+                    self.s.word(";");
+                }
+            }
+        }
+        self.maybe_print_trailing_comment(st.span, None)
+    }
+
+    crate fn print_block(&mut self, blk: &ast::Block) {
+        self.print_block_with_attrs(blk, &[])
+    }
+
+    crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
+        self.print_block_maybe_unclosed(blk, &[], false)
+    }
+
+    crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
+        self.print_block_maybe_unclosed(blk, attrs, true)
+    }
+
+    crate fn print_block_maybe_unclosed(
+        &mut self,
+        blk: &ast::Block,
+        attrs: &[ast::Attribute],
+        close_box: bool,
+    ) {
+        match blk.rules {
+            BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
+            BlockCheckMode::Default => (),
+        }
+        self.maybe_print_comment(blk.span.lo());
+        self.ann.pre(self, AnnNode::Block(blk));
+        self.bopen();
+
+        self.print_inner_attributes(attrs);
+
+        for (i, st) in blk.stmts.iter().enumerate() {
+            match st.kind {
+                ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
+                    self.maybe_print_comment(st.span.lo());
+                    self.space_if_not_bol();
+                    self.print_expr_outer_attr_style(expr, false);
+                    self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
+                }
+                _ => self.print_stmt(st),
+            }
+        }
+
+        self.bclose_maybe_open(blk.span, close_box);
+        self.ann.post(self, AnnNode::Block(blk))
+    }
+
+    /// Print a `let pat = scrutinee` expression.
+    crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
+        self.s.word("let ");
+
+        self.print_pat(pat);
+        self.s.space();
+
+        self.word_space("=");
+        self.print_expr_cond_paren(
+            scrutinee,
+            Self::cond_needs_par(scrutinee)
+                || parser::needs_par_as_let_scrutinee(scrutinee.precedence().order()),
+        )
+    }
+
+    fn print_else(&mut self, els: Option<&ast::Expr>) {
+        if let Some(_else) = els {
+            match _else.kind {
+                // Another `else if` block.
+                ast::ExprKind::If(ref i, ref then, ref e) => {
+                    self.cbox(INDENT_UNIT - 1);
+                    self.ibox(0);
+                    self.s.word(" else if ");
+                    self.print_expr_as_cond(i);
+                    self.s.space();
+                    self.print_block(then);
+                    self.print_else(e.as_deref())
+                }
+                // Final `else` block.
+                ast::ExprKind::Block(ref b, _) => {
+                    self.cbox(INDENT_UNIT - 1);
+                    self.ibox(0);
+                    self.s.word(" else ");
+                    self.print_block(b)
+                }
+                // Constraints would be great here!
+                _ => {
+                    panic!("print_if saw if with weird alternative");
+                }
+            }
+        }
+    }
+
+    crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
+        self.head("if");
+
+        self.print_expr_as_cond(test);
+        self.s.space();
+
+        self.print_block(blk);
+        self.print_else(elseopt)
+    }
+
+    crate fn print_mac(&mut self, m: &ast::MacCall) {
+        self.print_mac_common(
+            Some(MacHeader::Path(&m.path)),
+            true,
+            None,
+            m.args.delim(),
+            &m.args.inner_tokens(),
+            true,
+            m.span(),
+        );
+    }
+
+    fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
+        self.popen();
+        self.commasep_exprs(Inconsistent, args);
+        self.pclose()
+    }
+
+    crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
+        self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
+    }
+
+    /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
+    /// `if cond { ... }`.
+    crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
+        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+    }
+
+    /// Does `expr` need parenthesis when printed in a condition position?
+    fn cond_needs_par(expr: &ast::Expr) -> bool {
+        match expr.kind {
+            // These cases need parens due to the parse error observed in #26461: `if return {}`
+            // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
+            ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Break(..) => true,
+
+            _ => parser::contains_exterior_struct_lit(expr),
+        }
+    }
+
+    /// Prints `expr` or `(expr)` when `needs_par` holds.
+    fn print_expr_cond_paren(&mut self, expr: &ast::Expr, mut needs_par: bool) {
+        needs_par &= self.insert_extra_parens;
+        if needs_par {
+            self.popen();
+        }
+        self.print_expr(expr);
+        if needs_par {
+            self.pclose();
+        }
+    }
+
+    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+        self.ibox(INDENT_UNIT);
+        self.s.word("[");
+        self.print_inner_attributes_inline(attrs);
+        self.commasep_exprs(Inconsistent, &exprs[..]);
+        self.s.word("]");
+        self.end();
+    }
+
+    fn print_expr_anon_const(&mut self, expr: &ast::AnonConst, attrs: &[ast::Attribute]) {
+        self.ibox(INDENT_UNIT);
+        self.s.word("const");
+        self.print_inner_attributes_inline(attrs);
+        self.print_expr(&expr.value);
+        self.end();
+    }
+
+    fn print_expr_repeat(
+        &mut self,
+        element: &ast::Expr,
+        count: &ast::AnonConst,
+        attrs: &[ast::Attribute],
+    ) {
+        self.ibox(INDENT_UNIT);
+        self.s.word("[");
+        self.print_inner_attributes_inline(attrs);
+        self.print_expr(element);
+        self.word_space(";");
+        self.print_expr(&count.value);
+        self.s.word("]");
+        self.end();
+    }
+
+    fn print_expr_struct(
+        &mut self,
+        path: &ast::Path,
+        fields: &[ast::Field],
+        wth: &Option<P<ast::Expr>>,
+        attrs: &[ast::Attribute],
+    ) {
+        self.print_path(path, true, 0);
+        self.s.word("{");
+        self.print_inner_attributes_inline(attrs);
+        self.commasep_cmnt(
+            Consistent,
+            &fields[..],
+            |s, field| {
+                s.print_outer_attributes(&field.attrs);
+                s.ibox(INDENT_UNIT);
+                if !field.is_shorthand {
+                    s.print_ident(field.ident);
+                    s.word_space(":");
+                }
+                s.print_expr(&field.expr);
+                s.end();
+            },
+            |f| f.span,
+        );
+        match *wth {
+            Some(ref expr) => {
+                self.ibox(INDENT_UNIT);
+                if !fields.is_empty() {
+                    self.s.word(",");
+                    self.s.space();
+                }
+                self.s.word("..");
+                self.print_expr(expr);
+                self.end();
+            }
+            _ => {
+                if !fields.is_empty() {
+                    self.s.word(",")
+                }
+            }
+        }
+        self.s.word("}");
+    }
+
+    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+        self.popen();
+        self.print_inner_attributes_inline(attrs);
+        self.commasep_exprs(Inconsistent, &exprs[..]);
+        if exprs.len() == 1 {
+            self.s.word(",");
+        }
+        self.pclose()
+    }
+
+    fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
+        let prec = match func.kind {
+            ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
+            _ => parser::PREC_POSTFIX,
+        };
+
+        self.print_expr_maybe_paren(func, prec);
+        self.print_call_post(args)
+    }
+
+    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
+        let base_args = &args[1..];
+        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+        self.s.word(".");
+        self.print_ident(segment.ident);
+        if let Some(ref args) = segment.args {
+            self.print_generic_args(args, true);
+        }
+        self.print_call_post(base_args)
+    }
+
+    fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
+        let assoc_op = AssocOp::from_ast_binop(op.node);
+        let prec = assoc_op.precedence() as i8;
+        let fixity = assoc_op.fixity();
+
+        let (left_prec, right_prec) = match fixity {
+            Fixity::Left => (prec, prec + 1),
+            Fixity::Right => (prec + 1, prec),
+            Fixity::None => (prec + 1, prec + 1),
+        };
+
+        let left_prec = match (&lhs.kind, op.node) {
+            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
+            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
+            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
+            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
+                parser::PREC_FORCE_PAREN
+            }
+            // We are given `(let _ = a) OP b`.
+            //
+            // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
+            //   as the parser will interpret this as `(let _ = a) OP b`.
+            //
+            // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
+            //   parens are required since the parser would interpret `let a = b < c` as
+            //   `let a = (b < c)`. To achieve this, we force parens.
+            (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
+                parser::PREC_FORCE_PAREN
+            }
+            _ => left_prec,
+        };
+
+        self.print_expr_maybe_paren(lhs, left_prec);
+        self.s.space();
+        self.word_space(op.node.to_string());
+        self.print_expr_maybe_paren(rhs, right_prec)
+    }
+
+    fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
+        self.s.word(ast::UnOp::to_string(op));
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+    }
+
+    fn print_expr_addr_of(
+        &mut self,
+        kind: ast::BorrowKind,
+        mutability: ast::Mutability,
+        expr: &ast::Expr,
+    ) {
+        self.s.word("&");
+        match kind {
+            ast::BorrowKind::Ref => self.print_mutability(mutability, false),
+            ast::BorrowKind::Raw => {
+                self.word_nbsp("raw");
+                self.print_mutability(mutability, true);
+            }
+        }
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+    }
+
+    pub fn print_expr(&mut self, expr: &ast::Expr) {
+        self.print_expr_outer_attr_style(expr, true)
+    }
+
+    fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
+        self.maybe_print_comment(expr.span.lo());
+
+        let attrs = &expr.attrs;
+        if is_inline {
+            self.print_outer_attributes_inline(attrs);
+        } else {
+            self.print_outer_attributes(attrs);
+        }
+
+        self.ibox(INDENT_UNIT);
+        self.ann.pre(self, AnnNode::Expr(expr));
+        match expr.kind {
+            ast::ExprKind::Box(ref expr) => {
+                self.word_space("box");
+                self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
+            }
+            ast::ExprKind::Array(ref exprs) => {
+                self.print_expr_vec(&exprs[..], attrs);
+            }
+            ast::ExprKind::ConstBlock(ref anon_const) => {
+                self.print_expr_anon_const(anon_const, attrs);
+            }
+            ast::ExprKind::Repeat(ref element, ref count) => {
+                self.print_expr_repeat(element, count, attrs);
+            }
+            ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
+                self.print_expr_struct(path, &fields[..], wth, attrs);
+            }
+            ast::ExprKind::Tup(ref exprs) => {
+                self.print_expr_tup(&exprs[..], attrs);
+            }
+            ast::ExprKind::Call(ref func, ref args) => {
+                self.print_expr_call(func, &args[..]);
+            }
+            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
+                self.print_expr_method_call(segment, &args[..]);
+            }
+            ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
+                self.print_expr_binary(op, lhs, rhs);
+            }
+            ast::ExprKind::Unary(op, ref expr) => {
+                self.print_expr_unary(op, expr);
+            }
+            ast::ExprKind::AddrOf(k, m, ref expr) => {
+                self.print_expr_addr_of(k, m, expr);
+            }
+            ast::ExprKind::Lit(ref lit) => {
+                self.print_literal(lit);
+            }
+            ast::ExprKind::Cast(ref expr, ref ty) => {
+                let prec = AssocOp::As.precedence() as i8;
+                self.print_expr_maybe_paren(expr, prec);
+                self.s.space();
+                self.word_space("as");
+                self.print_type(ty);
+            }
+            ast::ExprKind::Type(ref expr, ref ty) => {
+                let prec = AssocOp::Colon.precedence() as i8;
+                self.print_expr_maybe_paren(expr, prec);
+                self.word_space(":");
+                self.print_type(ty);
+            }
+            ast::ExprKind::Let(ref pat, ref scrutinee) => {
+                self.print_let(pat, scrutinee);
+            }
+            ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
+                self.print_if(test, blk, elseopt.as_deref())
+            }
+            ast::ExprKind::While(ref test, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("while");
+                self.print_expr_as_cond(test);
+                self.s.space();
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("for");
+                self.print_pat(pat);
+                self.s.space();
+                self.word_space("in");
+                self.print_expr_as_cond(iter);
+                self.s.space();
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Loop(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("loop");
+                self.s.space();
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Match(ref expr, ref arms) => {
+                self.cbox(INDENT_UNIT);
+                self.ibox(INDENT_UNIT);
+                self.word_nbsp("match");
+                self.print_expr_as_cond(expr);
+                self.s.space();
+                self.bopen();
+                self.print_inner_attributes_no_trailing_hardbreak(attrs);
+                for arm in arms {
+                    self.print_arm(arm);
+                }
+                self.bclose(expr.span);
+            }
+            ast::ExprKind::Closure(
+                capture_clause,
+                asyncness,
+                movability,
+                ref decl,
+                ref body,
+                _,
+            ) => {
+                self.print_movability(movability);
+                self.print_asyncness(asyncness);
+                self.print_capture_clause(capture_clause);
+
+                self.print_fn_params_and_ret(decl, true);
+                self.s.space();
+                self.print_expr(body);
+                self.end(); // need to close a box
+
+                // a box will be closed by print_expr, but we didn't want an overall
+                // wrapper so we closed the corresponding opening. so create an
+                // empty box to satisfy the close.
+                self.ibox(0);
+            }
+            ast::ExprKind::Block(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                // containing cbox, will be closed by print-block at }
+                self.cbox(INDENT_UNIT);
+                // head-box, will be closed by print-block after {
+                self.ibox(0);
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Async(capture_clause, _, ref blk) => {
+                self.word_nbsp("async");
+                self.print_capture_clause(capture_clause);
+                self.s.space();
+                // cbox/ibox in analogy to the `ExprKind::Block` arm above
+                self.cbox(INDENT_UNIT);
+                self.ibox(0);
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Await(ref expr) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.s.word(".await");
+            }
+            ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
+                let prec = AssocOp::Assign.precedence() as i8;
+                self.print_expr_maybe_paren(lhs, prec + 1);
+                self.s.space();
+                self.word_space("=");
+                self.print_expr_maybe_paren(rhs, prec);
+            }
+            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+                let prec = AssocOp::Assign.precedence() as i8;
+                self.print_expr_maybe_paren(lhs, prec + 1);
+                self.s.space();
+                self.s.word(op.node.to_string());
+                self.word_space("=");
+                self.print_expr_maybe_paren(rhs, prec);
+            }
+            ast::ExprKind::Field(ref expr, ident) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.s.word(".");
+                self.print_ident(ident);
+            }
+            ast::ExprKind::Index(ref expr, ref index) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.s.word("[");
+                self.print_expr(index);
+                self.s.word("]");
+            }
+            ast::ExprKind::Range(ref start, ref end, limits) => {
+                // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
+                // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
+                // Here we use a fake precedence value so that any child with lower precedence than
+                // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
+                let fake_prec = AssocOp::LOr.precedence() as i8;
+                if let Some(ref e) = *start {
+                    self.print_expr_maybe_paren(e, fake_prec);
+                }
+                if limits == ast::RangeLimits::HalfOpen {
+                    self.s.word("..");
+                } else {
+                    self.s.word("..=");
+                }
+                if let Some(ref e) = *end {
+                    self.print_expr_maybe_paren(e, fake_prec);
+                }
+            }
+            ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
+            ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
+            ast::ExprKind::Break(opt_label, ref opt_expr) => {
+                self.s.word("break");
+                self.s.space();
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.s.space();
+                }
+                if let Some(ref expr) = *opt_expr {
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                    self.s.space();
+                }
+            }
+            ast::ExprKind::Continue(opt_label) => {
+                self.s.word("continue");
+                self.s.space();
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.s.space()
+                }
+            }
+            ast::ExprKind::Ret(ref result) => {
+                self.s.word("return");
+                if let Some(ref expr) = *result {
+                    self.s.word(" ");
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::InlineAsm(ref a) => {
+                enum AsmArg<'a> {
+                    Template(String),
+                    Operand(&'a InlineAsmOperand),
+                    Options(InlineAsmOptions),
+                }
+
+                let mut args = vec![];
+                args.push(AsmArg::Template(InlineAsmTemplatePiece::to_string(&a.template)));
+                args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
+                if !a.options.is_empty() {
+                    args.push(AsmArg::Options(a.options));
+                }
+
+                self.word("asm!");
+                self.popen();
+                self.commasep(Consistent, &args, |s, arg| match arg {
+                    AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked),
+                    AsmArg::Operand(op) => {
+                        let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r
+                        {
+                            InlineAsmRegOrRegClass::Reg(r) => {
+                                s.print_symbol(*r, ast::StrStyle::Cooked)
+                            }
+                            InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
+                        };
+                        match op {
+                            InlineAsmOperand::In { reg, expr } => {
+                                s.word("in");
+                                s.popen();
+                                print_reg_or_class(s, reg);
+                                s.pclose();
+                                s.space();
+                                s.print_expr(expr);
+                            }
+                            InlineAsmOperand::Out { reg, late, expr } => {
+                                s.word(if *late { "lateout" } else { "out" });
+                                s.popen();
+                                print_reg_or_class(s, reg);
+                                s.pclose();
+                                s.space();
+                                match expr {
+                                    Some(expr) => s.print_expr(expr),
+                                    None => s.word("_"),
+                                }
+                            }
+                            InlineAsmOperand::InOut { reg, late, expr } => {
+                                s.word(if *late { "inlateout" } else { "inout" });
+                                s.popen();
+                                print_reg_or_class(s, reg);
+                                s.pclose();
+                                s.space();
+                                s.print_expr(expr);
+                            }
+                            InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
+                                s.word(if *late { "inlateout" } else { "inout" });
+                                s.popen();
+                                print_reg_or_class(s, reg);
+                                s.pclose();
+                                s.space();
+                                s.print_expr(in_expr);
+                                s.space();
+                                s.word_space("=>");
+                                match out_expr {
+                                    Some(out_expr) => s.print_expr(out_expr),
+                                    None => s.word("_"),
+                                }
+                            }
+                            InlineAsmOperand::Const { expr } => {
+                                s.word("const");
+                                s.space();
+                                s.print_expr(expr);
+                            }
+                            InlineAsmOperand::Sym { expr } => {
+                                s.word("sym");
+                                s.space();
+                                s.print_expr(expr);
+                            }
+                        }
+                    }
+                    AsmArg::Options(opts) => {
+                        s.word("options");
+                        s.popen();
+                        let mut options = vec![];
+                        if opts.contains(InlineAsmOptions::PURE) {
+                            options.push("pure");
+                        }
+                        if opts.contains(InlineAsmOptions::NOMEM) {
+                            options.push("nomem");
+                        }
+                        if opts.contains(InlineAsmOptions::READONLY) {
+                            options.push("readonly");
+                        }
+                        if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) {
+                            options.push("preserves_flags");
+                        }
+                        if opts.contains(InlineAsmOptions::NORETURN) {
+                            options.push("noreturn");
+                        }
+                        if opts.contains(InlineAsmOptions::NOSTACK) {
+                            options.push("nostack");
+                        }
+                        if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
+                            options.push("att_syntax");
+                        }
+                        s.commasep(Inconsistent, &options, |s, &opt| {
+                            s.word(opt);
+                        });
+                        s.pclose();
+                    }
+                });
+                self.pclose();
+            }
+            ast::ExprKind::LlvmInlineAsm(ref a) => {
+                self.s.word("llvm_asm!");
+                self.popen();
+                self.print_symbol(a.asm, a.asm_str_style);
+                self.word_space(":");
+
+                self.commasep(Inconsistent, &a.outputs, |s, out| {
+                    let constraint = out.constraint.as_str();
+                    let mut ch = constraint.chars();
+                    match ch.next() {
+                        Some('=') if out.is_rw => {
+                            s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
+                        }
+                        _ => s.print_string(&constraint, ast::StrStyle::Cooked),
+                    }
+                    s.popen();
+                    s.print_expr(&out.expr);
+                    s.pclose();
+                });
+                self.s.space();
+                self.word_space(":");
+
+                self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
+                    s.print_symbol(co, ast::StrStyle::Cooked);
+                    s.popen();
+                    s.print_expr(o);
+                    s.pclose();
+                });
+                self.s.space();
+                self.word_space(":");
+
+                self.commasep(Inconsistent, &a.clobbers, |s, &co| {
+                    s.print_symbol(co, ast::StrStyle::Cooked);
+                });
+
+                let mut options = vec![];
+                if a.volatile {
+                    options.push("volatile");
+                }
+                if a.alignstack {
+                    options.push("alignstack");
+                }
+                if a.dialect == ast::LlvmAsmDialect::Intel {
+                    options.push("intel");
+                }
+
+                if !options.is_empty() {
+                    self.s.space();
+                    self.word_space(":");
+                    self.commasep(Inconsistent, &options, |s, &co| {
+                        s.print_string(co, ast::StrStyle::Cooked);
+                    });
+                }
+
+                self.pclose();
+            }
+            ast::ExprKind::MacCall(ref m) => self.print_mac(m),
+            ast::ExprKind::Paren(ref e) => {
+                self.popen();
+                self.print_inner_attributes_inline(attrs);
+                self.print_expr(e);
+                self.pclose();
+            }
+            ast::ExprKind::Yield(ref e) => {
+                self.s.word("yield");
+
+                if let Some(ref expr) = *e {
+                    self.s.space();
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::Try(ref e) => {
+                self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
+                self.s.word("?")
+            }
+            ast::ExprKind::TryBlock(ref blk) => {
+                self.head("try");
+                self.s.space();
+                self.print_block_with_attrs(blk, attrs)
+            }
+            ast::ExprKind::Err => {
+                self.popen();
+                self.s.word("/*ERROR*/");
+                self.pclose()
+            }
+        }
+        self.ann.post(self, AnnNode::Expr(expr));
+        self.end();
+    }
+
+    crate fn print_local_decl(&mut self, loc: &ast::Local) {
+        self.print_pat(&loc.pat);
+        if let Some(ref ty) = loc.ty {
+            self.word_space(":");
+            self.print_type(ty);
+        }
+    }
+
+    pub fn print_usize(&mut self, i: usize) {
+        self.s.word(i.to_string())
+    }
+
+    crate fn print_name(&mut self, name: Symbol) {
+        self.s.word(name.to_string());
+        self.ann.post(self, AnnNode::Name(&name))
+    }
+
+    fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
+        self.s.word("<");
+        self.print_type(&qself.ty);
+        if qself.position > 0 {
+            self.s.space();
+            self.word_space("as");
+            let depth = path.segments.len() - qself.position;
+            self.print_path(path, false, depth);
+        }
+        self.s.word(">");
+        self.s.word("::");
+        let item_segment = path.segments.last().unwrap();
+        self.print_ident(item_segment.ident);
+        if let Some(ref args) = item_segment.args {
+            self.print_generic_args(args, colons_before_params)
+        }
+    }
+
+    crate fn print_pat(&mut self, pat: &ast::Pat) {
+        self.maybe_print_comment(pat.span.lo());
+        self.ann.pre(self, AnnNode::Pat(pat));
+        /* Pat isn't normalized, but the beauty of it
+        is that it doesn't matter */
+        match pat.kind {
+            PatKind::Wild => self.s.word("_"),
+            PatKind::Ident(binding_mode, ident, ref sub) => {
+                match binding_mode {
+                    ast::BindingMode::ByRef(mutbl) => {
+                        self.word_nbsp("ref");
+                        self.print_mutability(mutbl, false);
+                    }
+                    ast::BindingMode::ByValue(ast::Mutability::Not) => {}
+                    ast::BindingMode::ByValue(ast::Mutability::Mut) => {
+                        self.word_nbsp("mut");
+                    }
+                }
+                self.print_ident(ident);
+                if let Some(ref p) = *sub {
+                    self.s.space();
+                    self.s.word_space("@");
+                    self.print_pat(p);
+                }
+            }
+            PatKind::TupleStruct(ref path, ref elts) => {
+                self.print_path(path, true, 0);
+                self.popen();
+                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+                self.pclose();
+            }
+            PatKind::Or(ref pats) => {
+                self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
+            }
+            PatKind::Path(None, ref path) => {
+                self.print_path(path, true, 0);
+            }
+            PatKind::Path(Some(ref qself), ref path) => {
+                self.print_qpath(path, qself, false);
+            }
+            PatKind::Struct(ref path, ref fields, etc) => {
+                self.print_path(path, true, 0);
+                self.nbsp();
+                self.word_space("{");
+                self.commasep_cmnt(
+                    Consistent,
+                    &fields[..],
+                    |s, f| {
+                        s.cbox(INDENT_UNIT);
+                        if !f.is_shorthand {
+                            s.print_ident(f.ident);
+                            s.word_nbsp(":");
+                        }
+                        s.print_pat(&f.pat);
+                        s.end();
+                    },
+                    |f| f.pat.span,
+                );
+                if etc {
+                    if !fields.is_empty() {
+                        self.word_space(",");
+                    }
+                    self.s.word("..");
+                }
+                self.s.space();
+                self.s.word("}");
+            }
+            PatKind::Tuple(ref elts) => {
+                self.popen();
+                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+                if elts.len() == 1 {
+                    self.s.word(",");
+                }
+                self.pclose();
+            }
+            PatKind::Box(ref inner) => {
+                self.s.word("box ");
+                self.print_pat(inner);
+            }
+            PatKind::Ref(ref inner, mutbl) => {
+                self.s.word("&");
+                if mutbl == ast::Mutability::Mut {
+                    self.s.word("mut ");
+                }
+                self.print_pat(inner);
+            }
+            PatKind::Lit(ref e) => self.print_expr(&**e),
+            PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
+                if let Some(e) = begin {
+                    self.print_expr(e);
+                    self.s.space();
+                }
+                match *end_kind {
+                    RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."),
+                    RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="),
+                    RangeEnd::Excluded => self.s.word(".."),
+                }
+                if let Some(e) = end {
+                    self.print_expr(e);
+                }
+            }
+            PatKind::Slice(ref elts) => {
+                self.s.word("[");
+                self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+                self.s.word("]");
+            }
+            PatKind::Rest => self.s.word(".."),
+            PatKind::Paren(ref inner) => {
+                self.popen();
+                self.print_pat(inner);
+                self.pclose();
+            }
+            PatKind::MacCall(ref m) => self.print_mac(m),
+        }
+        self.ann.post(self, AnnNode::Pat(pat))
+    }
+
+    fn print_arm(&mut self, arm: &ast::Arm) {
+        // Note, I have no idea why this check is necessary, but here it is.
+        if arm.attrs.is_empty() {
+            self.s.space();
+        }
+        self.cbox(INDENT_UNIT);
+        self.ibox(0);
+        self.maybe_print_comment(arm.pat.span.lo());
+        self.print_outer_attributes(&arm.attrs);
+        self.print_pat(&arm.pat);
+        self.s.space();
+        if let Some(ref e) = arm.guard {
+            self.word_space("if");
+            self.print_expr(e);
+            self.s.space();
+        }
+        self.word_space("=>");
+
+        match arm.body.kind {
+            ast::ExprKind::Block(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+
+                // The block will close the pattern's ibox.
+                self.print_block_unclosed_indent(blk);
+
+                // If it is a user-provided unsafe block, print a comma after it.
+                if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+                    self.s.word(",");
+                }
+            }
+            _ => {
+                self.end(); // Close the ibox for the pattern.
+                self.print_expr(&arm.body);
+                self.s.word(",");
+            }
+        }
+        self.end(); // Close enclosing cbox.
+    }
+
+    fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
+        match explicit_self.node {
+            SelfKind::Value(m) => {
+                self.print_mutability(m, false);
+                self.s.word("self")
+            }
+            SelfKind::Region(ref lt, m) => {
+                self.s.word("&");
+                self.print_opt_lifetime(lt);
+                self.print_mutability(m, false);
+                self.s.word("self")
+            }
+            SelfKind::Explicit(ref typ, m) => {
+                self.print_mutability(m, false);
+                self.s.word("self");
+                self.word_space(":");
+                self.print_type(typ)
+            }
+        }
+    }
+
+    fn print_fn_full(
+        &mut self,
+        sig: &ast::FnSig,
+        name: Ident,
+        generics: &ast::Generics,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+        body: Option<&ast::Block>,
+        attrs: &[ast::Attribute],
+    ) {
+        if body.is_some() {
+            self.head("");
+        }
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        self.print_fn(&sig.decl, sig.header, Some(name), generics);
+        if let Some(body) = body {
+            self.nbsp();
+            self.print_block_with_attrs(body, attrs);
+        } else {
+            self.s.word(";");
+        }
+    }
+
+    crate fn print_fn(
+        &mut self,
+        decl: &ast::FnDecl,
+        header: ast::FnHeader,
+        name: Option<Ident>,
+        generics: &ast::Generics,
+    ) {
+        self.print_fn_header_info(header);
+        if let Some(name) = name {
+            self.nbsp();
+            self.print_ident(name);
+        }
+        self.print_generic_params(&generics.params);
+        self.print_fn_params_and_ret(decl, false);
+        self.print_where_clause(&generics.where_clause)
+    }
+
+    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
+        self.word(open);
+        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
+        self.word(close);
+        self.print_fn_ret_ty(&decl.output)
+    }
+
+    crate fn print_movability(&mut self, movability: ast::Movability) {
+        match movability {
+            ast::Movability::Static => self.word_space("static"),
+            ast::Movability::Movable => {}
+        }
+    }
+
+    crate fn print_asyncness(&mut self, asyncness: ast::Async) {
+        if asyncness.is_async() {
+            self.word_nbsp("async");
+        }
+    }
+
+    crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
+        match capture_clause {
+            ast::CaptureBy::Value => self.word_space("move"),
+            ast::CaptureBy::Ref => {}
+        }
+    }
+
+    pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
+        if !bounds.is_empty() {
+            self.s.word(prefix);
+            let mut first = true;
+            for bound in bounds {
+                if !(first && prefix.is_empty()) {
+                    self.nbsp();
+                }
+                if first {
+                    first = false;
+                } else {
+                    self.word_space("+");
+                }
+
+                match bound {
+                    GenericBound::Trait(tref, modifier) => {
+                        if modifier == &TraitBoundModifier::Maybe {
+                            self.s.word("?");
+                        }
+                        self.print_poly_trait_ref(tref);
+                    }
+                    GenericBound::Outlives(lt) => self.print_lifetime(*lt),
+                }
+            }
+        }
+    }
+
+    crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
+        self.print_name(lifetime.ident.name)
+    }
+
+    crate fn print_lifetime_bounds(
+        &mut self,
+        lifetime: ast::Lifetime,
+        bounds: &ast::GenericBounds,
+    ) {
+        self.print_lifetime(lifetime);
+        if !bounds.is_empty() {
+            self.s.word(": ");
+            for (i, bound) in bounds.iter().enumerate() {
+                if i != 0 {
+                    self.s.word(" + ");
+                }
+                match bound {
+                    ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
+                    _ => panic!(),
+                }
+            }
+        }
+    }
+
+    crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
+        if generic_params.is_empty() {
+            return;
+        }
+
+        self.s.word("<");
+
+        self.commasep(Inconsistent, &generic_params, |s, param| {
+            s.print_outer_attributes_inline(&param.attrs);
+
+            match param.kind {
+                ast::GenericParamKind::Lifetime => {
+                    let lt = ast::Lifetime { id: param.id, ident: param.ident };
+                    s.print_lifetime_bounds(lt, &param.bounds)
+                }
+                ast::GenericParamKind::Type { ref default } => {
+                    s.print_ident(param.ident);
+                    s.print_type_bounds(":", &param.bounds);
+                    if let Some(ref default) = default {
+                        s.s.space();
+                        s.word_space("=");
+                        s.print_type(default)
+                    }
+                }
+                ast::GenericParamKind::Const { ref ty, kw_span: _ } => {
+                    s.word_space("const");
+                    s.print_ident(param.ident);
+                    s.s.space();
+                    s.word_space(":");
+                    s.print_type(ty);
+                    s.print_type_bounds(":", &param.bounds)
+                }
+            }
+        });
+
+        self.s.word(">");
+    }
+
+    crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
+        if where_clause.predicates.is_empty() && !where_clause.has_where_token {
+            return;
+        }
+
+        self.s.space();
+        self.word_space("where");
+
+        for (i, predicate) in where_clause.predicates.iter().enumerate() {
+            if i != 0 {
+                self.word_space(",");
+            }
+
+            match *predicate {
+                ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                    ref bound_generic_params,
+                    ref bounded_ty,
+                    ref bounds,
+                    ..
+                }) => {
+                    self.print_formal_generic_params(bound_generic_params);
+                    self.print_type(bounded_ty);
+                    self.print_type_bounds(":", bounds);
+                }
+                ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+                    ref lifetime,
+                    ref bounds,
+                    ..
+                }) => {
+                    self.print_lifetime_bounds(*lifetime, bounds);
+                }
+                ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
+                    ref lhs_ty,
+                    ref rhs_ty,
+                    ..
+                }) => {
+                    self.print_type(lhs_ty);
+                    self.s.space();
+                    self.word_space("=");
+                    self.print_type(rhs_ty);
+                }
+            }
+        }
+    }
+
+    crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
+        match tree.kind {
+            ast::UseTreeKind::Simple(rename, ..) => {
+                self.print_path(&tree.prefix, false, 0);
+                if let Some(rename) = rename {
+                    self.s.space();
+                    self.word_space("as");
+                    self.print_ident(rename);
+                }
+            }
+            ast::UseTreeKind::Glob => {
+                if !tree.prefix.segments.is_empty() {
+                    self.print_path(&tree.prefix, false, 0);
+                    self.s.word("::");
+                }
+                self.s.word("*");
+            }
+            ast::UseTreeKind::Nested(ref items) => {
+                if tree.prefix.segments.is_empty() {
+                    self.s.word("{");
+                } else {
+                    self.print_path(&tree.prefix, false, 0);
+                    self.s.word("::{");
+                }
+                self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| {
+                    this.print_use_tree(tree)
+                });
+                self.s.word("}");
+            }
+        }
+    }
+
+    pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
+        match mutbl {
+            ast::Mutability::Mut => self.word_nbsp("mut"),
+            ast::Mutability::Not => {
+                if print_const {
+                    self.word_nbsp("const");
+                }
+            }
+        }
+    }
+
+    crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
+        self.print_mutability(mt.mutbl, print_const);
+        self.print_type(&mt.ty)
+    }
+
+    crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
+        self.ibox(INDENT_UNIT);
+
+        self.print_outer_attributes_inline(&input.attrs);
+
+        match input.ty.kind {
+            ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
+            _ => {
+                if let Some(eself) = input.to_self() {
+                    self.print_explicit_self(&eself);
+                } else {
+                    let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
+                        ident.name == kw::Invalid
+                    } else {
+                        false
+                    };
+                    if !invalid {
+                        self.print_pat(&input.pat);
+                        self.s.word(":");
+                        self.s.space();
+                    }
+                    self.print_type(&input.ty);
+                }
+            }
+        }
+        self.end();
+    }
+
+    crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
+        if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
+            self.space_if_not_bol();
+            self.ibox(INDENT_UNIT);
+            self.word_space("->");
+            self.print_type(ty);
+            self.end();
+            self.maybe_print_comment(ty.span.lo());
+        }
+    }
+
+    crate fn print_ty_fn(
+        &mut self,
+        ext: ast::Extern,
+        unsafety: ast::Unsafe,
+        decl: &ast::FnDecl,
+        name: Option<Ident>,
+        generic_params: &[ast::GenericParam],
+    ) {
+        self.ibox(INDENT_UNIT);
+        if !generic_params.is_empty() {
+            self.s.word("for");
+            self.print_generic_params(generic_params);
+        }
+        let generics = ast::Generics {
+            params: Vec::new(),
+            where_clause: ast::WhereClause {
+                has_where_token: false,
+                predicates: Vec::new(),
+                span: rustc_span::DUMMY_SP,
+            },
+            span: rustc_span::DUMMY_SP,
+        };
+        let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
+        self.print_fn(decl, header, name, &generics);
+        self.end();
+    }
+
+    crate fn maybe_print_trailing_comment(
+        &mut self,
+        span: rustc_span::Span,
+        next_pos: Option<BytePos>,
+    ) {
+        if let Some(cmnts) = self.comments() {
+            if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
+                self.print_comment(&cmnt);
+            }
+        }
+    }
+
+    crate 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() {
+            self.s.hardbreak();
+        }
+        while let Some(ref cmnt) = self.next_comment() {
+            self.print_comment(cmnt);
+        }
+    }
+
+    crate fn print_fn_header_info(&mut self, header: ast::FnHeader) {
+        self.print_constness(header.constness);
+        self.print_asyncness(header.asyncness);
+        self.print_unsafety(header.unsafety);
+
+        match header.ext {
+            ast::Extern::None => {}
+            ast::Extern::Implicit => {
+                self.word_nbsp("extern");
+            }
+            ast::Extern::Explicit(abi) => {
+                self.word_nbsp("extern");
+                self.print_literal(&abi.as_lit());
+                self.nbsp();
+            }
+        }
+
+        self.s.word("fn")
+    }
+
+    crate fn print_unsafety(&mut self, s: ast::Unsafe) {
+        match s {
+            ast::Unsafe::No => {}
+            ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
+        }
+    }
+
+    crate fn print_constness(&mut self, s: ast::Const) {
+        match s {
+            ast::Const::No => {}
+            ast::Const::Yes(_) => self.word_nbsp("const"),
+        }
+    }
+
+    crate fn print_is_auto(&mut self, s: ast::IsAuto) {
+        match s {
+            ast::IsAuto::Yes => self.word_nbsp("auto"),
+            ast::IsAuto::No => {}
+        }
+    }
+}
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 03dbcc4..9c30934 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -76,6 +76,12 @@
 }
 
 #[derive(Clone, Encodable, Decodable)]
+pub enum InstructionSetAttr {
+    ArmA32,
+    ArmT32,
+}
+
+#[derive(Clone, Encodable, Decodable)]
 pub enum OptimizeAttr {
     None,
     Speed,
@@ -145,12 +151,10 @@
     pub feature: Symbol,
     /// whether the function has a `#[rustc_promotable]` attribute
     pub promotable: bool,
-    /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute
-    pub allow_const_fn_ptr: bool,
 }
 
 /// The available stability levels.
-#[derive(Encodable, Decodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
+#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub enum StabilityLevel {
     // Reason for the current stability level and the relevant rust-lang issue
@@ -190,7 +194,6 @@
     let mut stab: Option<Stability> = None;
     let mut const_stab: Option<ConstStability> = None;
     let mut promotable = false;
-    let mut allow_const_fn_ptr = false;
     let diagnostic = &sess.parse_sess.span_diagnostic;
 
     'outer: for attr in attrs_iter {
@@ -200,7 +203,6 @@
             sym::unstable,
             sym::stable,
             sym::rustc_promotable,
-            sym::rustc_allow_const_fn_ptr,
         ]
         .iter()
         .any(|&s| attr.has_name(s))
@@ -215,9 +217,6 @@
         if attr.has_name(sym::rustc_promotable) {
             promotable = true;
         }
-        if attr.has_name(sym::rustc_allow_const_fn_ptr) {
-            allow_const_fn_ptr = true;
-        }
         // attributes with data
         else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta {
             let meta = meta.as_ref().unwrap();
@@ -360,12 +359,8 @@
                             if sym::unstable == meta_name {
                                 stab = Some(Stability { level, feature });
                             } else {
-                                const_stab = Some(ConstStability {
-                                    level,
-                                    feature,
-                                    promotable: false,
-                                    allow_const_fn_ptr: false,
-                                });
+                                const_stab =
+                                    Some(ConstStability { level, feature, promotable: false });
                             }
                         }
                         (None, _, _) => {
@@ -440,12 +435,8 @@
                             if sym::stable == meta_name {
                                 stab = Some(Stability { level, feature });
                             } else {
-                                const_stab = Some(ConstStability {
-                                    level,
-                                    feature,
-                                    promotable: false,
-                                    allow_const_fn_ptr: false,
-                                });
+                                const_stab =
+                                    Some(ConstStability { level, feature, promotable: false });
                             }
                         }
                         (None, _) => {
@@ -464,18 +455,16 @@
     }
 
     // Merge the const-unstable info into the stability info
-    if promotable || allow_const_fn_ptr {
+    if promotable {
         if let Some(ref mut stab) = const_stab {
             stab.promotable = promotable;
-            stab.allow_const_fn_ptr = allow_const_fn_ptr;
         } else {
             struct_span_err!(
                 diagnostic,
                 item_sp,
                 E0717,
-                "rustc_promotable and rustc_allow_const_fn_ptr attributes \
-                      must be paired with either a rustc_const_unstable or a rustc_const_stable \
-                      attribute"
+                "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \
+                or a `rustc_const_stable` attribute"
             )
             .emit();
         }
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 5dafd6b..36cd6c2 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -81,7 +81,7 @@
         } // accept trailing commas
 
         // Parse options
-        if p.eat(&token::Ident(sym::options, false)) {
+        if p.eat_keyword(sym::options) {
             parse_options(&mut p, &mut args)?;
             allow_templates = false;
             continue;
@@ -101,19 +101,19 @@
         };
 
         let mut explicit_reg = false;
-        let op = if p.eat(&token::Ident(kw::In, false)) {
+        let op = if p.eat_keyword(kw::In) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
-        } else if p.eat(&token::Ident(sym::out, false)) {
+        } else if p.eat_keyword(sym::out) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
-        } else if p.eat(&token::Ident(sym::lateout, false)) {
+        } else if p.eat_keyword(sym::lateout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
-        } else if p.eat(&token::Ident(sym::inout, false)) {
+        } else if p.eat_keyword(sym::inout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = p.parse_expr()?;
             if p.eat(&token::FatArrow) {
@@ -123,7 +123,7 @@
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
-        } else if p.eat(&token::Ident(sym::inlateout, false)) {
+        } else if p.eat_keyword(sym::inlateout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = p.parse_expr()?;
             if p.eat(&token::FatArrow) {
@@ -133,10 +133,10 @@
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
-        } else if p.eat(&token::Ident(kw::Const, false)) {
+        } else if p.eat_keyword(kw::Const) {
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::Const { expr }
-        } else if p.eat(&token::Ident(sym::sym, false)) {
+        } else if p.eat_keyword(sym::sym) {
             let expr = p.parse_expr()?;
             match expr.kind {
                 ast::ExprKind::Path(..) => {}
@@ -164,7 +164,7 @@
             args.templates.push(template);
             continue;
         } else {
-            return Err(p.expect_one_of(&[], &[]).unwrap_err());
+            return p.unexpected();
         };
 
         allow_templates = false;
@@ -333,21 +333,22 @@
     p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
 
     while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
-        if p.eat(&token::Ident(sym::pure, false)) {
+        if p.eat_keyword(sym::pure) {
             try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
-        } else if p.eat(&token::Ident(sym::nomem, false)) {
+        } else if p.eat_keyword(sym::nomem) {
             try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
-        } else if p.eat(&token::Ident(sym::readonly, false)) {
+        } else if p.eat_keyword(sym::readonly) {
             try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
-        } else if p.eat(&token::Ident(sym::preserves_flags, false)) {
+        } else if p.eat_keyword(sym::preserves_flags) {
             try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
-        } else if p.eat(&token::Ident(sym::noreturn, false)) {
+        } else if p.eat_keyword(sym::noreturn) {
             try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
-        } else if p.eat(&token::Ident(sym::nostack, false)) {
+        } else if p.eat_keyword(sym::nostack) {
             try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
-        } else {
-            p.expect(&token::Ident(sym::att_syntax, false))?;
+        } else if p.eat_keyword(sym::att_syntax) {
             try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
+        } else {
+            return p.unexpected();
         }
 
         // Allow trailing commas
@@ -368,7 +369,7 @@
     explicit_reg: &mut bool,
 ) -> Result<ast::InlineAsmRegOrRegClass, DiagnosticBuilder<'a>> {
     p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
-    let result = match p.token.kind {
+    let result = match p.token.uninterpolate().kind {
         token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name),
         token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => {
             *explicit_reg = true;
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 2518171..5bfd8a2 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -120,8 +120,7 @@
         };
 
     if parser.token != token::Eof {
-        parser.expect_one_of(&[], &[])?;
-        unreachable!();
+        return parser.unexpected();
     }
 
     Ok(Assert { cond_expr, custom_message })
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index c4d1c6e..209158c 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -27,15 +27,15 @@
                 }
             }
         } else {
-            match e {
-                TokenTree::Token(Token { kind: token::Ident(name, _), .. }) => {
-                    res_str.push_str(&name.as_str())
-                }
-                _ => {
-                    cx.span_err(sp, "concat_idents! requires ident args.");
-                    return DummyResult::any(sp);
+            if let TokenTree::Token(token) = e {
+                if let Some((ident, _)) = token.ident() {
+                    res_str.push_str(&ident.name.as_str());
+                    continue;
                 }
             }
+
+            cx.span_err(sp, "concat_idents! requires ident args.");
+            return DummyResult::any(sp);
         }
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index f492499..2e52d2a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1137,12 +1137,9 @@
     /// for each of the self-args, carried in precomputed variables.
 
     /// ```{.text}
-    /// let __self0_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&self) };
-    /// let __self1_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&arg1) };
-    /// let __self2_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&arg2) };
+    /// let __self0_vi = std::intrinsics::discriminant_value(&self);
+    /// let __self1_vi = std::intrinsics::discriminant_value(&arg1);
+    /// let __self2_vi = std::intrinsics::discriminant_value(&arg2);
     ///
     /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
     ///     match (...) {
@@ -1325,7 +1322,7 @@
                 // Since we know that all the arguments will match if we reach
                 // the match expression we add the unreachable intrinsics as the
                 // result of the catch all which should help llvm in optimizing it
-                Some(deriving::call_intrinsic(cx, sp, sym::unreachable, vec![]))
+                Some(deriving::call_unreachable(cx, sp))
             }
             _ => None,
         };
@@ -1356,12 +1353,9 @@
             // with three Self args, builds three statements:
             //
             // ```
-            // let __self0_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&self) };
-            // let __self1_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&arg1) };
-            // let __self2_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&arg2) };
+            // let __self0_vi = std::intrinsics::discriminant_value(&self);
+            // let __self1_vi = std::intrinsics::discriminant_value(&arg1);
+            // let __self2_vi = std::intrinsics::discriminant_value(&arg2);
             // ```
             let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1);
 
@@ -1474,7 +1468,7 @@
             // derive Debug on such a type could here generate code
             // that needs the feature gate enabled.)
 
-            deriving::call_intrinsic(cx, sp, sym::unreachable, vec![])
+            deriving::call_unreachable(cx, sp)
         } else {
             // Final wrinkle: the self_args are expressions that deref
             // down to desired places, but we cannot actually deref
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 9c8e0fc..bf95093 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -68,7 +68,14 @@
 ) -> P<ast::Expr> {
     let span = cx.with_def_site_ctxt(span);
     let path = cx.std_path(&[sym::intrinsics, intrinsic]);
-    let call = cx.expr_call_global(span, path, args);
+    cx.expr_call_global(span, path, args)
+}
+
+/// Constructs an expression that calls the `unreachable` intrinsic.
+fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
+    let span = cx.with_def_site_ctxt(span);
+    let path = cx.std_path(&[sym::intrinsics, sym::unreachable]);
+    let call = cx.expr_call_global(span, path, vec![]);
 
     cx.expr_block(P(ast::Block {
         stmts: vec![cx.stmt_expr(call)],
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index ff81b5e..b69b00d 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -385,7 +385,7 @@
         if let Start = state {
             match c {
                 '1'..='9' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     match end.next_cp() {
                         // Yes, this *is* the parameter.
                         Some(('$', end2)) => {
@@ -427,7 +427,7 @@
                     move_to!(next);
                 }
                 '1'..='9' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Prec;
                     width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
                     move_to!(end);
@@ -441,7 +441,7 @@
         }
 
         if let WidthArg = state {
-            let end = at_next_cp_while(at, is_digit);
+            let end = at_next_cp_while(at, char::is_ascii_digit);
             match end.next_cp() {
                 Some(('$', end2)) => {
                     state = Prec;
@@ -473,7 +473,7 @@
         if let PrecInner = state {
             match c {
                 '*' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     match end.next_cp() {
                         Some(('$', end2)) => {
                             state = Length;
@@ -488,7 +488,7 @@
                     }
                 }
                 '0'..='9' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Length;
                     precision = Some(Num::from_str(at.slice_between(end).unwrap(), None));
                     move_to!(end);
@@ -563,12 +563,12 @@
 
     fn at_next_cp_while<F>(mut cur: Cur<'_>, mut pred: F) -> Cur<'_>
     where
-        F: FnMut(char) -> bool,
+        F: FnMut(&char) -> bool,
     {
         loop {
             match cur.next_cp() {
                 Some((c, next)) => {
-                    if pred(c) {
+                    if pred(&c) {
                         cur = next;
                     } else {
                         return cur;
@@ -579,14 +579,7 @@
         }
     }
 
-    fn is_digit(c: char) -> bool {
-        match c {
-            '0'..='9' => true,
-            _ => false,
-        }
-    }
-
-    fn is_flag(c: char) -> bool {
+    fn is_flag(c: &char) -> bool {
         match c {
             '0' | '-' | '+' | ' ' | '#' | '\'' => true,
             _ => false,
@@ -723,17 +716,11 @@
     }
 
     fn is_ident_head(c: char) -> bool {
-        match c {
-            'a'..='z' | 'A'..='Z' | '_' => true,
-            _ => false,
-        }
+        c.is_ascii_alphabetic() || c == '_'
     }
 
     fn is_ident_tail(c: char) -> bool {
-        match c {
-            '0'..='9' => true,
-            c => is_ident_head(c),
-        }
+        c.is_ascii_alphanumeric() || c == '_'
     }
 
     #[cfg(test)]
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 7075320..f76bbd8 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -13,8 +13,6 @@
 use smallvec::SmallVec;
 use std::rc::Rc;
 
-use rustc_data_structures::sync::Lrc;
-
 // These macros all relate to the file system; they either return
 // the column/row/filename of the expression, or they include
 // a given file into the current one.
@@ -216,7 +214,7 @@
         }
     };
     match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes)))),
+        Ok(bytes) => base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(bytes.into()))),
         Err(e) => {
             cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp)
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 0a60ca8..da74f0a 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -37,7 +37,7 @@
 pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
     let span_diagnostic = sess.diagnostic();
     let panic_strategy = sess.panic_strategy();
-    let platform_panic_strategy = sess.target.target.options.panic_strategy;
+    let platform_panic_strategy = sess.target.options.panic_strategy;
 
     // Check for #![reexport_test_harness_main = "some_name"] which gives the
     // main test function the name `some_name` without hygiene. This needs to be
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 04792b3..586b9d0 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -15,7 +15,7 @@
 snap = "1"
 tracing = "0.1"
 rustc_middle = { path = "../rustc_middle" }
-rustc-demangle = "0.1"
+rustc-demangle = "0.1.18"
 rustc_attr = { path = "../rustc_attr" }
 rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index bc1d9e1..d02bc41 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -3,17 +3,23 @@
 use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
+use rustc_span::symbol::sym;
 
 use crate::llvm::{self, False, True};
 use crate::ModuleLlvm;
 
-pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: AllocatorKind) {
+pub(crate) unsafe fn codegen(
+    tcx: TyCtxt<'_>,
+    mods: &mut ModuleLlvm,
+    kind: AllocatorKind,
+    has_alloc_error_handler: bool,
+) {
     let llcx = &*mods.llcx;
     let llmod = mods.llmod();
-    let usize = match &tcx.sess.target.target.target_pointer_width[..] {
-        "16" => llvm::LLVMInt16TypeInContext(llcx),
-        "32" => llvm::LLVMInt32TypeInContext(llcx),
-        "64" => llvm::LLVMInt64TypeInContext(llcx),
+    let usize = match tcx.sess.target.pointer_width {
+        16 => llvm::LLVMInt16TypeInContext(llcx),
+        32 => llvm::LLVMInt32TypeInContext(llcx),
+        64 => llvm::LLVMInt64TypeInContext(llcx),
         tws => bug!("Unsupported target word size for int: {}", tws),
     };
     let i8 = llvm::LLVMInt8TypeInContext(llcx);
@@ -51,7 +57,7 @@
         let name = format!("__rust_{}", method.name);
         let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
 
-        if tcx.sess.target.target.options.default_hidden_visibility {
+        if tcx.sess.target.options.default_hidden_visibility {
             llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
         }
         if tcx.sess.must_emit_unwind_tables() {
@@ -82,4 +88,41 @@
         }
         llvm::LLVMDisposeBuilder(llbuilder);
     }
+
+    // rust alloc error handler
+    let args = [usize, usize]; // size, align
+
+    let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
+    let name = format!("__rust_alloc_error_handler");
+    let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
+    // -> ! DIFlagNoReturn
+    llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
+
+    if tcx.sess.target.options.default_hidden_visibility {
+        llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+    }
+    if tcx.sess.must_emit_unwind_tables() {
+        attributes::emit_uwtable(llfn, true);
+    }
+
+    let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
+    let callee = kind.fn_name(sym::oom);
+    let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
+    // -> ! DIFlagNoReturn
+    llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, callee);
+    llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+
+    let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
+
+    let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
+    llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
+    let args = args
+        .iter()
+        .enumerate()
+        .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
+        .collect::<Vec<_>>();
+    let ret = llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
+    llvm::LLVMSetTailCall(ret, True);
+    llvm::LLVMBuildRetVoid(llbuilder);
+    llvm::LLVMDisposeBuilder(llbuilder);
 }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index f801f84..b096664 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -60,7 +60,7 @@
 
         // Default per-arch clobbers
         // Basically what clang does
-        let arch_clobbers = match &self.sess().target.target.arch[..] {
+        let arch_clobbers = match &self.sess().target.arch[..] {
             "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
             "mips" | "mips64" => vec!["~{$1}"],
             _ => Vec::new(),
@@ -259,7 +259,7 @@
                 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
                 InlineAsmArch::Nvptx64 => {}
                 InlineAsmArch::Hexagon => {}
-                InlineAsmArch::Mips => {}
+                InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -710,6 +710,7 @@
             // 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()),
             _ => value,
         },
         _ => value,
@@ -785,6 +786,7 @@
             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()),
             _ => value,
         },
         _ => value,
@@ -854,6 +856,7 @@
             // 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(),
             _ => layout.llvm_type(cx),
         },
         _ => layout.llvm_type(cx),
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 227a87f..2075c2e 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -6,7 +6,7 @@
 use rustc_data_structures::const_cstr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::query::Providers;
@@ -18,7 +18,7 @@
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, Attribute};
 use crate::llvm_util;
-pub use rustc_attr::{InlineAttr, OptimizeAttr};
+pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 
 use crate::context::CodegenCx;
 use crate::value::Value;
@@ -31,7 +31,7 @@
         Hint => Attribute::InlineHint.apply_llfn(Function, val),
         Always => Attribute::AlwaysInline.apply_llfn(Function, val),
         Never => {
-            if cx.tcx().sess.target.target.arch != "amdgpu" {
+            if cx.tcx().sess.target.arch != "amdgpu" {
                 Attribute::NoInline.apply_llfn(Function, val);
             }
         }
@@ -91,8 +91,7 @@
         // The function name varies on platforms.
         // See test/CodeGen/mcount.c in clang.
         let mcount_name =
-            CString::new(cx.sess().target.target.options.target_mcount.as_str().as_bytes())
-                .unwrap();
+            CString::new(cx.sess().target.options.target_mcount.as_str().as_bytes()).unwrap();
 
         llvm::AddFunctionAttrStringValue(
             llfn,
@@ -106,7 +105,7 @@
 fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     // Only use stack probes if the target specification indicates that we
     // should be using stack probes
-    if !cx.sess().target.target.options.stack_probes {
+    if !cx.sess().target.options.stack_probes {
         return;
     }
 
@@ -175,7 +174,6 @@
         .split(',')
         .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)));
     sess.target
-        .target
         .options
         .features
         .split(',')
@@ -194,6 +192,18 @@
     );
 }
 
+pub fn apply_tune_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+    if let Some(tune) = llvm_util::tune_cpu(cx.tcx.sess) {
+        let tune_cpu = SmallCStr::new(tune);
+        llvm::AddFunctionAttrStringValue(
+            llfn,
+            llvm::AttributePlace::Function,
+            const_cstr!("tune-cpu"),
+            tune_cpu.as_c_str(),
+        );
+    }
+}
+
 /// Sets the `NonLazyBind` LLVM attribute on a given function,
 /// assuming the codegen options allow skipping the PLT.
 pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
@@ -294,12 +304,18 @@
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
         Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
     }
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
+        llvm::AddFunctionAttrString(llfn, Function, const_cstr!("cmse_nonsecure_entry"));
+    }
     sanitize(cx, codegen_fn_attrs.no_sanitize, llfn);
 
     // Always annotate functions with the target-cpu they are compiled for.
     // Without this, ThinLTO won't inline Rust functions into Clang generated
     // functions (because Clang annotates functions this way too).
     apply_target_cpu_attr(cx, llfn);
+    // tune-cpu is only conveyed through the attribute for our purpose.
+    // The target doesn't care; the subtarget reads our attribute.
+    apply_tune_cpu_attr(cx, llfn);
 
     let features = llvm_target_features(cx.tcx.sess)
         .map(|s| s.to_string())
@@ -307,6 +323,10 @@
             let feature = &f.as_str();
             format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
         }))
+        .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
+            InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
+            InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
+        }))
         .collect::<Vec<String>>()
         .join(",");
 
@@ -323,7 +343,7 @@
     // Note that currently the `wasm-import-module` doesn't do anything, but
     // eventually LLVM 7 should read this and ferry the appropriate import
     // module to the output file.
-    if cx.tcx.sess.target.target.arch == "wasm32" {
+    if cx.tcx.sess.target.arch == "wasm32" {
         if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
             llvm::AddFunctionAttrStringValue(
                 llfn,
@@ -345,25 +365,7 @@
     }
 }
 
-pub fn provide(providers: &mut Providers) {
-    providers.supported_target_features = |tcx, cnum| {
-        assert_eq!(cnum, LOCAL_CRATE);
-        if tcx.sess.opts.actually_rustdoc {
-            // rustdoc needs to be able to document functions that use all the features, so
-            // provide them all.
-            llvm_util::all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
-        } else {
-            llvm_util::supported_target_features(tcx.sess)
-                .iter()
-                .map(|&(a, b)| (a.to_string(), b))
-                .collect()
-        }
-    };
-
-    provide_extern(providers);
-}
-
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_both(providers: &mut Providers) {
     providers.wasm_import_module_map = |tcx, cnum| {
         // Build up a map from DefId to a `NativeLib` structure, where
         // `NativeLib` internally contains information about
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index a115a1e..595655b 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -206,7 +206,7 @@
     }
 
     fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
-        let kind = &*self.config.sess.target.target.options.archive_format;
+        let kind = &*self.config.sess.target.options.archive_format;
         kind.parse().map_err(|_| kind)
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 4b2d590..ff312ba 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -2,14 +2,14 @@
     self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers,
 };
 use crate::llvm::archive_ro::ArchiveRO;
-use crate::llvm::{self, False, True};
+use crate::llvm::{self, build_string, False, True};
 use crate::{LlvmCodegenBackend, ModuleLlvm};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{FatalError, Handler};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
@@ -22,16 +22,14 @@
 use std::ffi::{CStr, CString};
 use std::fs::File;
 use std::io;
-use std::mem;
 use std::path::Path;
 use std::ptr;
 use std::slice;
 use std::sync::Arc;
 
-/// We keep track of past LTO imports that were used to produce the current set
-/// of compiled object files that we might choose to reuse during this
-/// compilation session.
-pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-imports.bin";
+/// We keep track of the computed LTO cache keys from the previous
+/// session to determine which CGUs we can reuse.
+pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
 
 pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
     match crate_type {
@@ -485,31 +483,31 @@
         )
         .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?;
 
+        let data = ThinData(data);
+
         info!("thin LTO data created");
 
-        let (import_map_path, prev_import_map, curr_import_map) =
-            if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir {
-                let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME);
-                // If previous imports have been deleted, or we get an IO error
-                // reading the file storing them, then we'll just use `None` as the
-                // prev_import_map, which will force the code to be recompiled.
-                let prev = if path.exists() {
-                    ThinLTOImportMaps::load_from_file(&path).ok()
-                } else {
-                    None
-                };
-                let curr = ThinLTOImportMaps::from_thin_lto_data(data);
-                (Some(path), prev, curr)
-            } else {
-                // If we don't compile incrementally, we don't need to load the
-                // import data from LLVM.
-                assert!(green_modules.is_empty());
-                let curr = ThinLTOImportMaps::default();
-                (None, None, curr)
-            };
-        info!("thin LTO import map loaded");
-
-        let data = ThinData(data);
+        let (key_map_path, prev_key_map, curr_key_map) = if let Some(ref incr_comp_session_dir) =
+            cgcx.incr_comp_session_dir
+        {
+            let path = incr_comp_session_dir.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME);
+            // If the previous file was deleted, or we get an IO error
+            // reading the file, then we'll just use `None` as the
+            // prev_key_map, which will force the code to be recompiled.
+            let prev =
+                if path.exists() { ThinLTOKeysMap::load_from_file(&path).ok() } else { None };
+            let curr = ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names);
+            (Some(path), prev, curr)
+        } else {
+            // If we don't compile incrementally, we don't need to load the
+            // import data from LLVM.
+            assert!(green_modules.is_empty());
+            let curr = ThinLTOKeysMap::default();
+            (None, None, curr)
+        };
+        info!("thin LTO cache key map loaded");
+        info!("prev_key_map: {:#?}", prev_key_map);
+        info!("curr_key_map: {:#?}", curr_key_map);
 
         // Throw our data in an `Arc` as we'll be sharing it across threads. We
         // also put all memory referenced by the C++ data (buffers, ids, etc)
@@ -528,60 +526,14 @@
         info!("checking which modules can be-reused and which have to be re-optimized.");
         for (module_index, module_name) in shared.module_names.iter().enumerate() {
             let module_name = module_name_to_str(module_name);
-
-            // If (1.) the module hasn't changed, and (2.) none of the modules
-            // it imports from have changed, *and* (3.) the import and export
-            // sets themselves have not changed from the previous compile when
-            // it was last ThinLTO'ed, then we can re-use the post-ThinLTO
-            // version of the module. Otherwise, freshly perform LTO
-            // optimization.
-            //
-            // (Note that globally, the export set is just the inverse of the
-            // import set.)
-            //
-            // For further justification of why the above is necessary and sufficient,
-            // see the LLVM blog post on ThinLTO:
-            //
-            // http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html
-            //
-            // which states the following:
-            //
-            // ```quote
-            // any particular ThinLTO backend must be redone iff:
-            //
-            // 1. The corresponding (primary) module’s bitcode changed
-            // 2. The list of imports into or exports from the module changed
-            // 3. The bitcode for any module being imported from has changed
-            // 4. Any global analysis result affecting either the primary module
-            //    or anything it imports has changed.
-            // ```
-            //
-            // This strategy means we can always save the computed imports as
-            // canon: when we reuse the post-ThinLTO version, condition (3.)
-            // ensures that the current import set is the same as the previous
-            // one. (And of course, when we don't reuse the post-ThinLTO
-            // version, the current import set *is* the correct one, since we
-            // are doing the ThinLTO in this current compilation cycle.)
-            //
-            // For more discussion, see rust-lang/rust#59535 (where the import
-            // issue was discovered) and rust-lang/rust#69798 (where the
-            // analogous export issue was discovered).
-            if let (Some(prev_import_map), true) =
-                (prev_import_map.as_ref(), green_modules.contains_key(module_name))
+            if let (Some(prev_key_map), true) =
+                (prev_key_map.as_ref(), green_modules.contains_key(module_name))
             {
                 assert!(cgcx.incr_comp_session_dir.is_some());
 
-                let prev_imports = prev_import_map.imports_of(module_name);
-                let curr_imports = curr_import_map.imports_of(module_name);
-                let prev_exports = prev_import_map.exports_of(module_name);
-                let curr_exports = curr_import_map.exports_of(module_name);
-                let imports_all_green = curr_imports
-                    .iter()
-                    .all(|imported_module| green_modules.contains_key(imported_module));
-                if imports_all_green
-                    && equivalent_as_sets(prev_imports, curr_imports)
-                    && equivalent_as_sets(prev_exports, curr_exports)
-                {
+                // If a module exists in both the current and the previous session,
+                // and has the same LTO cache key in both sessions, then we can re-use it
+                if prev_key_map.keys.get(module_name) == curr_key_map.keys.get(module_name) {
                     let work_product = green_modules[module_name].clone();
                     copy_jobs.push(work_product);
                     info!(" - {}: re-used", module_name);
@@ -599,10 +551,10 @@
         }
 
         // Save the current ThinLTO import information for the next compilation
-        // session, overwriting the previous serialized imports (if any).
-        if let Some(path) = import_map_path {
-            if let Err(err) = curr_import_map.save_to_file(&path) {
-                let msg = format!("Error while writing ThinLTO import data: {}", err);
+        // session, overwriting the previous serialized data (if any).
+        if let Some(path) = key_map_path {
+            if let Err(err) = curr_key_map.save_to_file(&path) {
+                let msg = format!("Error while writing ThinLTO key data: {}", err);
                 return Err(write::llvm_err(&diag_handler, &msg));
             }
         }
@@ -611,24 +563,6 @@
     }
 }
 
-/// Given two slices, each with no repeat elements. returns true if and only if
-/// the two slices have the same contents when considered as sets (i.e. when
-/// element order is disregarded).
-fn equivalent_as_sets(a: &[String], b: &[String]) -> bool {
-    // cheap path: unequal lengths means cannot possibly be set equivalent.
-    if a.len() != b.len() {
-        return false;
-    }
-    // fast path: before building new things, check if inputs are equivalent as is.
-    if a == b {
-        return true;
-    }
-    // slow path: general set comparison.
-    let a: FxHashSet<&str> = a.iter().map(|s| s.as_str()).collect();
-    let b: FxHashSet<&str> = b.iter().map(|s| s.as_str()).collect();
-    a == b
-}
-
 pub(crate) fn run_pass_manager(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     module: &ModuleCodegen<ModuleLlvm>,
@@ -942,113 +876,56 @@
     Ok(module)
 }
 
-/// Summarizes module import/export relationships used by LLVM's ThinLTO pass.
-///
-/// Note that we tend to have two such instances of `ThinLTOImportMaps` in use:
-/// one loaded from a file that represents the relationships used during the
-/// compilation associated with the incremetnal build artifacts we are
-/// attempting to reuse, and another constructed via `from_thin_lto_data`, which
-/// captures the relationships of ThinLTO in the current compilation.
+/// Maps LLVM module identifiers to their corresponding LLVM LTO cache keys
 #[derive(Debug, Default)]
-pub struct ThinLTOImportMaps {
-    // key = llvm name of importing module, value = list of modules it imports from
-    imports: FxHashMap<String, Vec<String>>,
-    // key = llvm name of exporting module, value = list of modules it exports to
-    exports: FxHashMap<String, Vec<String>>,
+pub struct ThinLTOKeysMap {
+    // key = llvm name of importing module, value = LLVM cache key
+    keys: FxHashMap<String, String>,
 }
 
-impl ThinLTOImportMaps {
-    /// Returns modules imported by `llvm_module_name` during some ThinLTO pass.
-    fn imports_of(&self, llvm_module_name: &str) -> &[String] {
-        self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
-    }
-
-    /// Returns modules exported by `llvm_module_name` during some ThinLTO pass.
-    fn exports_of(&self, llvm_module_name: &str) -> &[String] {
-        self.exports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
-    }
-
+impl ThinLTOKeysMap {
     fn save_to_file(&self, path: &Path) -> io::Result<()> {
         use std::io::Write;
         let file = File::create(path)?;
         let mut writer = io::BufWriter::new(file);
-        for (importing_module_name, imported_modules) in &self.imports {
-            writeln!(writer, "{}", importing_module_name)?;
-            for imported_module in imported_modules {
-                writeln!(writer, " {}", imported_module)?;
-            }
-            writeln!(writer)?;
+        for (module, key) in &self.keys {
+            writeln!(writer, "{} {}", module, key)?;
         }
         Ok(())
     }
 
-    fn load_from_file(path: &Path) -> io::Result<ThinLTOImportMaps> {
+    fn load_from_file(path: &Path) -> io::Result<Self> {
         use std::io::BufRead;
-        let mut imports = FxHashMap::default();
-        let mut exports: FxHashMap<_, Vec<_>> = FxHashMap::default();
-        let mut current_module: Option<String> = None;
-        let mut current_imports: Vec<String> = vec![];
+        let mut keys = FxHashMap::default();
         let file = File::open(path)?;
         for line in io::BufReader::new(file).lines() {
             let line = line?;
-            if line.is_empty() {
-                let importing_module = current_module.take().expect("Importing module not set");
-                for imported in &current_imports {
-                    exports.entry(imported.clone()).or_default().push(importing_module.clone());
-                }
-                imports.insert(importing_module, mem::replace(&mut current_imports, vec![]));
-            } else if line.starts_with(' ') {
-                // Space marks an imported module
-                assert_ne!(current_module, None);
-                current_imports.push(line.trim().to_string());
-            } else {
-                // Otherwise, beginning of a new module (must be start or follow empty line)
-                assert_eq!(current_module, None);
-                current_module = Some(line.trim().to_string());
-            }
+            let mut split = line.split(" ");
+            let module = split.next().unwrap();
+            let key = split.next().unwrap();
+            assert_eq!(split.next(), None, "Expected two space-separated values, found {:?}", line);
+            keys.insert(module.to_string(), key.to_string());
         }
-        Ok(ThinLTOImportMaps { imports, exports })
+        Ok(Self { keys })
     }
 
-    /// Loads the ThinLTO import map from ThinLTOData.
-    unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImportMaps {
-        unsafe extern "C" fn imported_module_callback(
-            payload: *mut libc::c_void,
-            importing_module_name: *const libc::c_char,
-            imported_module_name: *const libc::c_char,
-        ) {
-            let map = &mut *(payload as *mut ThinLTOImportMaps);
-            let importing_module_name = CStr::from_ptr(importing_module_name);
-            let importing_module_name = module_name_to_str(&importing_module_name);
-            let imported_module_name = CStr::from_ptr(imported_module_name);
-            let imported_module_name = module_name_to_str(&imported_module_name);
-
-            if !map.imports.contains_key(importing_module_name) {
-                map.imports.insert(importing_module_name.to_owned(), vec![]);
-            }
-
-            map.imports
-                .get_mut(importing_module_name)
-                .unwrap()
-                .push(imported_module_name.to_owned());
-
-            if !map.exports.contains_key(imported_module_name) {
-                map.exports.insert(imported_module_name.to_owned(), vec![]);
-            }
-
-            map.exports
-                .get_mut(imported_module_name)
-                .unwrap()
-                .push(importing_module_name.to_owned());
-        }
-
-        let mut map = ThinLTOImportMaps::default();
-        llvm::LLVMRustGetThinLTOModuleImports(
-            data,
-            imported_module_callback,
-            &mut map as *mut _ as *mut libc::c_void,
-        );
-        map
+    fn from_thin_lto_modules(
+        data: &ThinData,
+        modules: &[llvm::ThinLTOModule],
+        names: &[CString],
+    ) -> Self {
+        let keys = modules
+            .iter()
+            .zip(names.iter())
+            .map(|(module, name)| {
+                let key = build_string(|rust_str| unsafe {
+                    llvm::LLVMRustComputeLTOCacheKey(rust_str, module.identifier, data.0);
+                })
+                .expect("Invalid ThinLTO module key");
+                (name.clone().into_string().unwrap(), key)
+            })
+            .collect();
+        Self { keys }
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 937821e..092d1ce 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -128,40 +128,40 @@
     let (opt_level, _) = to_llvm_opt_settings(optlvl);
     let use_softfp = sess.opts.cg.soft_float;
 
-    let ffunction_sections = sess.target.target.options.function_sections;
+    let ffunction_sections = sess.target.options.function_sections;
     let fdata_sections = ffunction_sections;
 
     let code_model = to_llvm_code_model(sess.code_model());
 
     let features = attributes::llvm_target_features(sess).collect::<Vec<_>>();
-    let mut singlethread = sess.target.target.options.singlethread;
+    let mut singlethread = sess.target.options.singlethread;
 
     // On the wasm target once the `atomics` feature is enabled that means that
     // we're no longer single-threaded, or otherwise we don't want LLVM to
     // lower atomic operations to single-threaded operations.
     if singlethread
-        && sess.target.target.llvm_target.contains("wasm32")
+        && sess.target.llvm_target.contains("wasm32")
         && sess.target_features.contains(&sym::atomics)
     {
         singlethread = false;
     }
 
-    let triple = SmallCStr::new(&sess.target.target.llvm_target);
+    let triple = SmallCStr::new(&sess.target.llvm_target);
     let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
     let features = features.join(",");
     let features = CString::new(features).unwrap();
-    let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname);
-    let trap_unreachable = sess.target.target.options.trap_unreachable;
+    let abi = SmallCStr::new(&sess.target.options.llvm_abiname);
+    let trap_unreachable = sess.target.options.trap_unreachable;
     let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
 
     let asm_comments = sess.asm_comments();
-    let relax_elf_relocations = sess.target.target.options.relax_elf_relocations;
+    let relax_elf_relocations = sess.target.options.relax_elf_relocations;
 
     let use_init_array = !sess
         .opts
         .debugging_opts
         .use_ctors_section
-        .unwrap_or(sess.target.target.options.use_ctors_section);
+        .unwrap_or(sess.target.options.use_ctors_section);
 
     Arc::new(move || {
         let tm = unsafe {
@@ -344,6 +344,13 @@
             .expect("non-UTF8 diagnostic");
             diag_handler.warn(&msg);
         }
+        llvm::diagnostic::Unsupported(diagnostic_ref) => {
+            let msg = llvm::build_string(|s| {
+                llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
+            })
+            .expect("non-UTF8 diagnostic");
+            diag_handler.err(&msg);
+        }
         llvm::diagnostic::UnknownDiagnostic(..) => {}
     }
 }
@@ -929,8 +936,8 @@
         llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
     } else {
         let asm = "
-            .section .llvmbc,\"e\"
-            .section .llvmcmd,\"e\"
+            .section .llvmbc,\"a\"
+            .section .llvmcmd,\"a\"
         ";
         llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
     }
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index f35708b..1090d4a 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -60,7 +60,7 @@
         unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
     unsafe {
         llvm::LLVMSetInitializer(llglobal, llconst);
-        let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
+        let section_name = metadata::metadata_section_name(&tcx.sess.target);
         let name = SmallCStr::new(section_name);
         llvm::LLVMSetSection(llglobal, name.as_ptr());
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 0c172dc..491191d 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -16,7 +16,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 use rustc_target::abi::{self, Align, Size};
 use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
@@ -139,6 +139,8 @@
         unsafe { llvm::LLVMGetInsertBlock(self.llbuilder) }
     }
 
+    fn set_span(&mut self, _span: Span) {}
+
     fn position_at_end(&mut self, llbb: &'ll BasicBlock) {
         unsafe {
             llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb);
@@ -306,8 +308,8 @@
         use rustc_middle::ty::{Int, Uint};
 
         let new_kind = match ty.kind() {
-            Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.ptr_width)),
-            Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.ptr_width)),
+            Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
+            Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
             t @ (Uint(_) | Int(_)) => t.clone(),
             _ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
         };
@@ -539,7 +541,7 @@
     }
 
     fn range_metadata(&mut self, load: &'ll Value, range: Range<u128>) {
-        if self.sess().target.target.arch == "amdgpu" {
+        if self.sess().target.arch == "amdgpu" {
             // amdgpu/LLVM does something weird and thinks a i64 value is
             // split into a v2i32, halving the bitwidth LLVM expects,
             // tripping an assertion. So, for now, just disable this
@@ -669,7 +671,7 @@
         // WebAssembly has saturating floating point to integer casts if the
         // `nontrapping-fptoint` target feature is activated. We'll use those if
         // they are available.
-        if self.sess().target.target.arch == "wasm32"
+        if self.sess().target.arch == "wasm32"
             && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
         {
             let src_ty = self.cx.val_ty(val);
@@ -694,7 +696,7 @@
         // WebAssembly has saturating floating point to integer casts if the
         // `nontrapping-fptoint` target feature is activated. We'll use those if
         // they are available.
-        if self.sess().target.target.arch == "wasm32"
+        if self.sess().target.arch == "wasm32"
             && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
         {
             let src_ty = self.cx.val_ty(val);
@@ -1425,7 +1427,7 @@
     }
 
     fn wasm_and_missing_nontrapping_fptoint(&self) -> bool {
-        self.sess().target.target.arch == "wasm32"
+        self.sess().target.arch == "wasm32"
             && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 4afd906..e200347 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -176,7 +176,7 @@
         // should use dllimport for functions.
         if cx.use_dll_storage_attrs
             && tcx.is_dllimport_foreign_item(instance_def_id)
-            && tcx.sess.target.target.target_env != "gnu"
+            && tcx.sess.target.target_env != "gnu"
         {
             unsafe {
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 6d3582d..b57a233 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -92,7 +92,7 @@
     // The target may require greater alignment for globals than the type does.
     // Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
     // which can force it to be smaller.  Rust doesn't support this yet.
-    if let Some(min) = cx.sess().target.target.options.min_global_align {
+    if let Some(min) = cx.sess().target.options.min_global_align {
         match Align::from_bits(min) {
             Ok(min) => align = align.max(min),
             Err(err) => {
@@ -283,7 +283,7 @@
             // argument validation.
             debug_assert!(
                 !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
-                    && self.tcx.sess.target.target.options.is_like_windows
+                    && self.tcx.sess.target.options.is_like_windows
                     && self.tcx.sess.opts.cg.prefer_dynamic)
             );
 
@@ -437,7 +437,7 @@
                 // will use load-unaligned instructions instead, and thus avoiding the crash.
                 //
                 // We could remove this hack whenever we decide to drop macOS 10.10 support.
-                if self.tcx.sess.target.target.options.is_like_osx {
+                if self.tcx.sess.target.options.is_like_osx {
                     // The `inspect` method is okay here because we checked relocations, and
                     // because we are doing this access to inspect the final interpreter state
                     // (not as part of the interpreter execution).
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 1696f35..150cedd 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -118,18 +118,18 @@
     let mod_name = SmallCStr::new(mod_name);
     let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
 
-    let mut target_data_layout = sess.target.target.data_layout.clone();
+    let mut target_data_layout = sess.target.data_layout.clone();
     if llvm_util::get_major_version() < 9 {
         target_data_layout = strip_function_ptr_alignment(target_data_layout);
     }
     if llvm_util::get_major_version() < 10 {
-        if sess.target.target.arch == "x86" || sess.target.target.arch == "x86_64" {
+        if sess.target.arch == "x86" || sess.target.arch == "x86_64" {
             target_data_layout = strip_x86_address_spaces(target_data_layout);
         }
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
-    if sess.target.target.options.is_builtin {
+    if sess.target.options.is_builtin {
         let tm = crate::back::write::create_informational_target_machine(tcx.sess);
         llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
         llvm::LLVMRustDisposeTargetMachine(tm);
@@ -160,7 +160,7 @@
             bug!(
                 "data-layout for builtin `{}` target, `{}`, \
                   differs from LLVM default, `{}`",
-                sess.target.target.llvm_target,
+                sess.target.llvm_target,
                 target_data_layout,
                 llvm_data_layout
             );
@@ -170,7 +170,7 @@
     let data_layout = SmallCStr::new(&target_data_layout);
     llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
 
-    let llvm_target = SmallCStr::new(&sess.target.target.llvm_target);
+    let llvm_target = SmallCStr::new(&sess.target.llvm_target);
     llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
 
     if sess.relocation_model() == RelocModel::Pic {
@@ -190,7 +190,7 @@
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
-    if sess.target.target.options.is_like_msvc {
+    if sess.target.options.is_like_msvc {
         match sess.opts.cg.control_flow_guard {
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
@@ -265,7 +265,7 @@
         // linker will take care of everything. Fixing this problem will likely
         // require adding a few attributes to Rust itself (feature gated at the
         // start) and then strongly recommending static linkage on Windows!
-        let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_windows;
+        let use_dll_storage_attrs = tcx.sess.target.options.is_like_windows;
 
         let check_overflow = tcx.sess.overflow_checks();
 
@@ -417,7 +417,8 @@
     }
 
     fn apply_target_cpu_attr(&self, llfn: &'ll Value) {
-        attributes::apply_target_cpu_attr(self, llfn)
+        attributes::apply_target_cpu_attr(self, llfn);
+        attributes::apply_tune_cpu_attr(self, llfn);
     }
 
     fn create_used_variable(&self) {
@@ -838,7 +839,7 @@
             return eh_catch_typeinfo;
         }
         let tcx = self.tcx;
-        assert!(self.sess().target.target.options.is_like_emscripten);
+        assert!(self.sess().target.options.is_like_emscripten);
         let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
             Some(def_id) => self.get_static(def_id),
             _ => {
@@ -877,7 +878,7 @@
 
 impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
     fn target_spec(&self) -> &Target {
-        &self.tcx.sess.target.target
+        &self.tcx.sess.target
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index ec6c177..0098555 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -126,6 +126,7 @@
                 let (filenames_index, _) = self.filenames.insert_full(c_filename);
                 virtual_file_mapping.push(filenames_index as u32);
             }
+            debug!("Adding counter {:?} to map for {:?}", counter, region,);
             mapping_regions.push(CounterMappingRegion::code_region(
                 counter,
                 current_file_id,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 29edd660..79721ff 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -67,5 +67,5 @@
 
     !omit_gdb_pretty_printer_section
         && cx.sess().opts.debuginfo != DebugInfo::None
-        && cx.sess().target.target.options.emit_debug_gdb_scripts
+        && cx.sess().target.options.emit_debug_gdb_scripts
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 987149c..5587e6e 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -874,7 +874,7 @@
 
     // When targeting MSVC, emit MSVC style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc;
+    let msvc_like_names = cx.tcx.sess.target.options.is_like_msvc;
 
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
@@ -985,7 +985,7 @@
     // if multiple object files with the same `DW_AT_name` are linked together.
     // As a workaround we generate unique names for each object file. Those do
     // not correspond to an actual source file but that should be harmless.
-    if tcx.sess.target.target.options.is_like_osx {
+    if tcx.sess.target.options.is_like_osx {
         name_in_debuginfo.push("@");
         name_in_debuginfo.push(codegen_unit_name);
     }
@@ -1401,7 +1401,7 @@
 /// on MSVC we have to use the fallback mode, because LLVM doesn't
 /// lower variant parts to PDB.
 fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
-    cx.sess().target.target.options.is_like_msvc
+    cx.sess().target.options.is_like_msvc
 }
 
 // FIXME(eddyb) maybe precompute this? Right now it's computed once
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 7cdd366..80e0e7b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -120,14 +120,12 @@
         // for macOS to understand. For more info see #11352
         // This can be overridden using --llvm-opts -dwarf-version,N.
         // Android has the same issue (#22398)
-        if cx.sess().target.target.options.is_like_osx
-            || cx.sess().target.target.options.is_like_android
-        {
-            llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), 2)
+        if let Some(version) = cx.sess().target.options.dwarf_version {
+            llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version)
         }
 
         // Indicate that we want CodeView debug information on MSVC
-        if cx.sess().target.target.options.is_like_msvc {
+        if cx.sess().target.options.is_like_msvc {
             llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1)
         }
 
@@ -348,7 +346,7 @@
             });
 
             // Arguments types
-            if cx.sess().target.target.options.is_like_msvc {
+            if cx.sess().target.options.is_like_msvc {
                 // FIXME(#42800):
                 // There is a bug in MSDIA that leads to a crash when it encounters
                 // a fixed-size array of `u8` or something zero-sized in a
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
index 66ae9d7..517246c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
@@ -38,7 +38,7 @@
         // For MSVC, omit the column number.
         // Otherwise, emit it. This mimics clang behaviour.
         // See discussion in https://github.com/rust-lang/rust/issues/42921
-        if self.sess().target.target.options.is_like_msvc {
+        if self.sess().target.options.is_like_msvc {
             DebugLoc { file, line, col: None }
         } else {
             DebugLoc { file, line, col }
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index a3d6882..9face77 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -42,7 +42,7 @@
     // be merged.
     llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global);
 
-    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.target.options.disable_redzone) {
+    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.options.disable_redzone) {
         llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 7f5b09e..e9900e8 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -334,8 +334,8 @@
         self.call(expect, &[cond, self.const_bool(expected)], None)
     }
 
-    fn sideeffect(&mut self) {
-        if self.tcx.sess.opts.debugging_opts.insert_sideeffect {
+    fn sideeffect(&mut self, unconditional: bool) {
+        if unconditional || self.tcx.sess.opts.debugging_opts.insert_sideeffect {
             let fnname = self.get_intrinsic(&("llvm.sideeffect"));
             self.call(fnname, &[], None);
         }
@@ -367,7 +367,7 @@
         bx.store(bx.const_i32(0), dest, ret_align);
     } else if wants_msvc_seh(bx.sess()) {
         codegen_msvc_try(bx, try_func, data, catch_func, dest);
-    } else if bx.sess().target.target.options.is_like_emscripten {
+    } else if bx.sess().target.options.is_like_emscripten {
         codegen_emcc_try(bx, try_func, data, catch_func, dest);
     } else {
         codegen_gnu_try(bx, try_func, data, catch_func, dest);
@@ -390,7 +390,7 @@
 ) {
     let llfn = get_rust_try_fn(bx, &mut |mut bx| {
         bx.set_personality_fn(bx.eh_personality());
-        bx.sideeffect();
+        bx.sideeffect(false);
 
         let mut normal = bx.build_sibling_block("normal");
         let mut catchswitch = bx.build_sibling_block("catchswitch");
@@ -553,7 +553,7 @@
         //      call %catch_func(%data, %ptr)
         //      ret 1
 
-        bx.sideeffect();
+        bx.sideeffect(false);
 
         let mut then = bx.build_sibling_block("then");
         let mut catch = bx.build_sibling_block("catch");
@@ -615,7 +615,7 @@
         //      call %catch_func(%data, %catch_data)
         //      ret 1
 
-        bx.sideeffect();
+        bx.sideeffect(false);
 
         let mut then = bx.build_sibling_block("then");
         let mut catch = bx.build_sibling_block("catch");
@@ -673,17 +673,9 @@
 fn gen_fn<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     name: &str,
-    inputs: Vec<Ty<'tcx>>,
-    output: Ty<'tcx>,
+    rust_fn_sig: ty::PolyFnSig<'tcx>,
     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
 ) -> &'ll Value {
-    let rust_fn_sig = ty::Binder::bind(cx.tcx.mk_fn_sig(
-        inputs.into_iter(),
-        output,
-        false,
-        hir::Unsafety::Unsafe,
-        Abi::Rust,
-    ));
     let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
     let llfn = cx.declare_fn(name, &fn_abi);
     cx.set_frame_pointer_elimination(llfn);
@@ -710,22 +702,31 @@
     // Define the type up front for the signature of the rust_try function.
     let tcx = cx.tcx;
     let i8p = tcx.mk_mut_ptr(tcx.types.i8);
-    let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
+    // `unsafe fn(*mut i8) -> ()`
+    let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
         iter::once(i8p),
         tcx.mk_unit(),
         false,
         hir::Unsafety::Unsafe,
         Abi::Rust,
     )));
-    let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
+    // `unsafe fn(*mut i8, *mut i8) -> ()`
+    let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
         [i8p, i8p].iter().cloned(),
         tcx.mk_unit(),
         false,
         hir::Unsafety::Unsafe,
         Abi::Rust,
     )));
-    let output = tcx.types.i32;
-    let rust_try = gen_fn(cx, "__rust_try", vec![try_fn_ty, i8p, catch_fn_ty], output, codegen);
+    // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
+    let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
+        vec![try_fn_ty, i8p, catch_fn_ty].into_iter(),
+        tcx.types.i32,
+        false,
+        hir::Unsafety::Unsafe,
+        Abi::Rust,
+    ));
+    let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
     cx.rust_try_fn.set(Some(rust_try));
     rust_try
 }
@@ -793,14 +794,18 @@
         require_simd!(arg_tys[1], "argument");
         let v_len = arg_tys[1].simd_size(tcx);
         require!(
-            m_len == v_len,
+            // Allow masks for vectors with fewer than 8 elements to be
+            // represented with a u8 or i8.
+            m_len == v_len || (m_len == 8 && v_len < 8),
             "mismatched lengths: mask length `{}` != other vector length `{}`",
             m_len,
             v_len
         );
         let i1 = bx.type_i1();
-        let i1xn = bx.type_vector(i1, m_len);
-        let m_i1s = bx.bitcast(args[0].immediate(), i1xn);
+        let im = bx.type_ix(v_len);
+        let i1xn = bx.type_vector(i1, v_len);
+        let m_im = bx.trunc(args[0].immediate(), im);
+        let m_i1s = bx.bitcast(m_im, i1xn);
         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
     }
 
@@ -1718,10 +1723,10 @@
 fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> {
     match ty.kind() {
         ty::Int(t) => {
-            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true))
+            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), true))
         }
         ty::Uint(t) => {
-            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false))
+            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), false))
         }
         _ => None,
     }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index f14493e..5974b59 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -23,18 +23,17 @@
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{ErrorReported, FatalError, Handler};
-use rustc_middle::dep_graph::{DepGraph, WorkProduct};
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_serialize::json;
-use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest};
+use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 
 use std::any::Any;
 use std::ffi::CStr;
-use std::fs;
 use std::sync::Arc;
 
 mod back {
@@ -95,8 +94,9 @@
         tcx: TyCtxt<'tcx>,
         mods: &mut ModuleLlvm,
         kind: AllocatorKind,
+        has_alloc_error_handler: bool,
     ) {
-        unsafe { allocator::codegen(tcx, mods, kind) }
+        unsafe { allocator::codegen(tcx, mods, kind, has_alloc_error_handler) }
     }
     fn compile_codegen_unit(
         &self,
@@ -115,6 +115,9 @@
     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
         llvm_util::target_cpu(sess)
     }
+    fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
+        llvm_util::tune_cpu(sess)
+    }
 }
 
 impl WriteBackendMethods for LlvmCodegenBackend {
@@ -248,11 +251,11 @@
     }
 
     fn provide(&self, providers: &mut ty::query::Providers) {
-        attributes::provide(providers);
+        attributes::provide_both(providers);
     }
 
     fn provide_extern(&self, providers: &mut ty::query::Providers) {
-        attributes::provide_extern(providers);
+        attributes::provide_both(providers);
     }
 
     fn codegen_crate<'tcx>(
@@ -273,47 +276,27 @@
         &self,
         ongoing_codegen: Box<dyn Any>,
         sess: &Session,
-        dep_graph: &DepGraph,
-    ) -> Result<Box<dyn Any>, ErrorReported> {
+    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
         let (codegen_results, work_products) = ongoing_codegen
             .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
             .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
             .join(sess);
-        if sess.opts.debugging_opts.incremental_info {
-            rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results);
-        }
 
-        sess.time("serialize_work_products", move || {
-            rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)
+        sess.time("llvm_dump_timing_file", || {
+            if sess.opts.debugging_opts.llvm_time_trace {
+                llvm_util::time_trace_profiler_finish("llvm_timings.json");
+            }
         });
 
-        sess.compile_status()?;
-
-        Ok(Box::new(codegen_results))
+        Ok((codegen_results, work_products))
     }
 
     fn link(
         &self,
         sess: &Session,
-        codegen_results: Box<dyn Any>,
+        codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported> {
-        let codegen_results = codegen_results
-            .downcast::<CodegenResults>()
-            .expect("Expected CodegenResults, found Box<Any>");
-
-        if sess.opts.debugging_opts.no_link {
-            // FIXME: use a binary format to encode the `.rlink` file
-            let rlink_data = json::encode(&codegen_results).map_err(|err| {
-                sess.fatal(&format!("failed to encode rlink: {}", err));
-            })?;
-            let rlink_file = outputs.with_extension(config::RLINK_EXT);
-            fs::write(&rlink_file, rlink_data).map_err(|err| {
-                sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
-            })?;
-            return Ok(());
-        }
-
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
         sess.time("link_crate", || {
@@ -330,16 +313,6 @@
             );
         });
 
-        // Now that we won't touch anything in the incremental compilation directory
-        // any more, we can finalize it (which involves renaming it)
-        rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);
-
-        sess.time("llvm_dump_timing_file", || {
-            if sess.opts.debugging_opts.llvm_time_trace {
-                llvm_util::time_trace_profiler_finish("llvm_timings.json");
-            }
-        });
-
         Ok(())
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
index 47f5c94..ccd3e42 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
@@ -118,6 +118,7 @@
     InlineAsm(InlineAsmDiagnostic<'ll>),
     PGO(&'ll DiagnosticInfo),
     Linker(&'ll DiagnosticInfo),
+    Unsupported(&'ll DiagnosticInfo),
 
     /// LLVM has other types that we do not wrap here.
     UnknownDiagnostic(&'ll DiagnosticInfo),
@@ -159,6 +160,7 @@
 
             Dk::PGOProfile => PGO(di),
             Dk::Linker => Linker(di),
+            Dk::Unsupported => Unsupported(di),
 
             _ => UnknownDiagnostic(di),
         }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 45c5f56..4c1fee0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -483,6 +483,7 @@
     OptimizationFailure,
     PGOProfile,
     Linker,
+    Unsupported,
 }
 
 /// LLVMRustDiagnosticLevel
@@ -2361,4 +2362,10 @@
         bytecode_len: usize,
     ) -> bool;
     pub fn LLVMRustLinkerFree(linker: &'a mut Linker<'a>);
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustComputeLTOCacheKey(
+        key_out: &RustString,
+        mod_id: *const c_char,
+        data: &ThinLTOData,
+    );
 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index c09e365..53a404e 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -37,6 +37,12 @@
     }
 }
 
+pub fn AddFunctionAttrString(llfn: &'a Value, idx: AttributePlace, attr: &CStr) {
+    unsafe {
+        LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), std::ptr::null())
+    }
+}
+
 #[derive(Copy, Clone)]
 pub enum AttributePlace {
     ReturnValue,
@@ -112,11 +118,6 @@
     }
 }
 
-pub fn set_thread_local(global: &'a Value, is_thread_local: bool) {
-    unsafe {
-        LLVMSetThreadLocal(global, is_thread_local as Bool);
-    }
-}
 pub fn set_thread_local_mode(global: &'a Value, mode: ThreadLocalMode) {
     unsafe {
         LLVMSetThreadLocalMode(global, mode);
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 900f2df..9c1e1b8f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,12 +1,12 @@
 use crate::back::write::create_informational_target_machine;
 use crate::llvm;
 use libc::c_int;
+use rustc_codegen_ssa::target_features::supported_target_features;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_feature::UnstableFeatures;
 use rustc_middle::bug;
 use rustc_session::config::PrintRequest;
 use rustc_session::Session;
-use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy};
 use std::ffi::CString;
@@ -46,7 +46,7 @@
 }
 
 unsafe fn configure_llvm(sess: &Session) {
-    let n_args = sess.opts.cg.llvm_args.len() + sess.target.target.options.llvm_args.len();
+    let n_args = sess.opts.cg.llvm_args.len() + sess.target.options.llvm_args.len();
     let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
     let mut llvm_args = Vec::with_capacity(n_args + 1);
 
@@ -57,7 +57,7 @@
     }
 
     let cg_opts = sess.opts.cg.llvm_args.iter();
-    let tg_opts = sess.target.target.options.llvm_args.iter();
+    let tg_opts = sess.target.options.llvm_args.iter();
     let sess_args = cg_opts.chain(tg_opts);
 
     let user_specified_args: FxHashSet<_> =
@@ -88,7 +88,7 @@
             .opts
             .debugging_opts
             .merge_functions
-            .unwrap_or(sess.target.target.options.merge_functions)
+            .unwrap_or(sess.target.options.merge_functions)
         {
             MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
             MergeFunctions::Aliases => {
@@ -96,9 +96,7 @@
             }
         }
 
-        if sess.target.target.target_os == "emscripten"
-            && sess.panic_strategy() == PanicStrategy::Unwind
-        {
+        if sess.target.target_os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
             add("-enable-emscripten-cxx-exceptions", false);
         }
 
@@ -122,7 +120,7 @@
 
     llvm::LLVMInitializePasses();
 
-    ::rustc_llvm::initialize_available_targets();
+    rustc_llvm::initialize_available_targets();
 
     llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
 }
@@ -139,142 +137,8 @@
 // WARNING: the features after applying `to_llvm_feature` must be known
 // to LLVM or the feature detection code will walk past the end of the feature
 // array, leading to crashes.
-
-const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("aclass", Some(sym::arm_target_feature)),
-    ("mclass", Some(sym::arm_target_feature)),
-    ("rclass", Some(sym::arm_target_feature)),
-    ("dsp", Some(sym::arm_target_feature)),
-    ("neon", Some(sym::arm_target_feature)),
-    ("crc", Some(sym::arm_target_feature)),
-    ("crypto", Some(sym::arm_target_feature)),
-    ("v5te", Some(sym::arm_target_feature)),
-    ("v6", Some(sym::arm_target_feature)),
-    ("v6k", Some(sym::arm_target_feature)),
-    ("v6t2", Some(sym::arm_target_feature)),
-    ("v7", Some(sym::arm_target_feature)),
-    ("v8", Some(sym::arm_target_feature)),
-    ("vfp2", Some(sym::arm_target_feature)),
-    ("vfp3", Some(sym::arm_target_feature)),
-    ("vfp4", Some(sym::arm_target_feature)),
-    // This is needed for inline assembly, but shouldn't be stabilized as-is
-    // since it should be enabled per-function using #[instruction_set], not
-    // #[target_feature].
-    ("thumb-mode", Some(sym::arm_target_feature)),
-];
-
-const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("fp", Some(sym::aarch64_target_feature)),
-    ("neon", Some(sym::aarch64_target_feature)),
-    ("sve", Some(sym::aarch64_target_feature)),
-    ("crc", Some(sym::aarch64_target_feature)),
-    ("crypto", Some(sym::aarch64_target_feature)),
-    ("ras", Some(sym::aarch64_target_feature)),
-    ("lse", Some(sym::aarch64_target_feature)),
-    ("rdm", Some(sym::aarch64_target_feature)),
-    ("fp16", Some(sym::aarch64_target_feature)),
-    ("rcpc", Some(sym::aarch64_target_feature)),
-    ("dotprod", Some(sym::aarch64_target_feature)),
-    ("tme", Some(sym::aarch64_target_feature)),
-    ("v8.1a", Some(sym::aarch64_target_feature)),
-    ("v8.2a", Some(sym::aarch64_target_feature)),
-    ("v8.3a", Some(sym::aarch64_target_feature)),
-];
-
-const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("adx", Some(sym::adx_target_feature)),
-    ("aes", None),
-    ("avx", None),
-    ("avx2", None),
-    ("avx512bw", Some(sym::avx512_target_feature)),
-    ("avx512cd", Some(sym::avx512_target_feature)),
-    ("avx512dq", Some(sym::avx512_target_feature)),
-    ("avx512er", Some(sym::avx512_target_feature)),
-    ("avx512f", Some(sym::avx512_target_feature)),
-    ("avx512ifma", Some(sym::avx512_target_feature)),
-    ("avx512pf", Some(sym::avx512_target_feature)),
-    ("avx512vbmi", Some(sym::avx512_target_feature)),
-    ("avx512vl", Some(sym::avx512_target_feature)),
-    ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
-    ("bmi1", None),
-    ("bmi2", None),
-    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
-    ("f16c", Some(sym::f16c_target_feature)),
-    ("fma", None),
-    ("fxsr", None),
-    ("lzcnt", None),
-    ("movbe", Some(sym::movbe_target_feature)),
-    ("pclmulqdq", None),
-    ("popcnt", None),
-    ("rdrand", None),
-    ("rdseed", None),
-    ("rtm", Some(sym::rtm_target_feature)),
-    ("sha", None),
-    ("sse", None),
-    ("sse2", None),
-    ("sse3", None),
-    ("sse4.1", None),
-    ("sse4.2", None),
-    ("sse4a", Some(sym::sse4a_target_feature)),
-    ("ssse3", None),
-    ("tbm", Some(sym::tbm_target_feature)),
-    ("xsave", None),
-    ("xsavec", None),
-    ("xsaveopt", None),
-    ("xsaves", None),
-];
-
-const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("hvx", Some(sym::hexagon_target_feature)),
-    ("hvx-length128b", Some(sym::hexagon_target_feature)),
-];
-
-const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("altivec", Some(sym::powerpc_target_feature)),
-    ("power8-altivec", Some(sym::powerpc_target_feature)),
-    ("power9-altivec", Some(sym::powerpc_target_feature)),
-    ("power8-vector", Some(sym::powerpc_target_feature)),
-    ("power9-vector", Some(sym::powerpc_target_feature)),
-    ("vsx", Some(sym::powerpc_target_feature)),
-];
-
-const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
-    &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];
-
-const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("m", Some(sym::riscv_target_feature)),
-    ("a", Some(sym::riscv_target_feature)),
-    ("c", Some(sym::riscv_target_feature)),
-    ("f", Some(sym::riscv_target_feature)),
-    ("d", Some(sym::riscv_target_feature)),
-    ("e", Some(sym::riscv_target_feature)),
-];
-
-const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("simd128", Some(sym::wasm_target_feature)),
-    ("atomics", Some(sym::wasm_target_feature)),
-    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
-];
-
-/// When rustdoc is running, provide a list of all known features so that all their respective
-/// primitives may be documented.
-///
-/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
-pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
-    std::iter::empty()
-        .chain(ARM_ALLOWED_FEATURES.iter())
-        .chain(AARCH64_ALLOWED_FEATURES.iter())
-        .chain(X86_ALLOWED_FEATURES.iter())
-        .chain(HEXAGON_ALLOWED_FEATURES.iter())
-        .chain(POWERPC_ALLOWED_FEATURES.iter())
-        .chain(MIPS_ALLOWED_FEATURES.iter())
-        .chain(RISCV_ALLOWED_FEATURES.iter())
-        .chain(WASM_ALLOWED_FEATURES.iter())
-        .cloned()
-}
-
 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
-    let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch };
+    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
     match (arch, s) {
         ("x86", "pclmulqdq") => "pclmul",
         ("x86", "rdrand") => "rdrnd",
@@ -306,20 +170,6 @@
         .collect()
 }
 
-pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
-    match &*sess.target.target.arch {
-        "arm" => ARM_ALLOWED_FEATURES,
-        "aarch64" => AARCH64_ALLOWED_FEATURES,
-        "x86" | "x86_64" => X86_ALLOWED_FEATURES,
-        "hexagon" => HEXAGON_ALLOWED_FEATURES,
-        "mips" | "mips64" => MIPS_ALLOWED_FEATURES,
-        "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
-        "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
-        "wasm32" => WASM_ALLOWED_FEATURES,
-        _ => &[],
-    }
-}
-
 pub fn print_version() {
     // Can be called without initializing LLVM
     unsafe {
@@ -350,11 +200,7 @@
     }
 }
 
-pub fn target_cpu(sess: &Session) -> &str {
-    let name = match sess.opts.cg.target_cpu {
-        Some(ref s) => &**s,
-        None => &*sess.target.target.options.cpu,
-    };
+fn handle_native(name: &str) -> &str {
     if name != "native" {
         return name;
     }
@@ -365,3 +211,19 @@
         str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
     }
 }
+
+pub fn target_cpu(sess: &Session) -> &str {
+    let name = match sess.opts.cg.target_cpu {
+        Some(ref s) => &**s,
+        None => &*sess.target.options.cpu,
+    };
+
+    handle_native(name)
+}
+
+pub fn tune_cpu(sess: &Session) -> Option<&str> {
+    match sess.opts.debugging_opts.tune_cpu {
+        Some(ref s) => Some(handle_native(&**s)),
+        None => None,
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 22ed4dd..5f820f83 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -52,7 +52,7 @@
     let next = bx.inbounds_gep(addr, &[full_direct_size]);
     bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
 
-    if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target.target_endian == "big" {
+    if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target_endian == "big" {
         let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
         let adjusted = bx.inbounds_gep(addr, &[adjusted_size]);
         (bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align)
@@ -105,7 +105,7 @@
     let mut end = bx.build_sibling_block("va_arg.end");
     let zero = bx.const_i32(0);
     let offset_align = Align::from_bytes(4).unwrap();
-    assert!(&*bx.tcx().sess.target.target.target_endian == "little");
+    assert!(&*bx.tcx().sess.target.target_endian == "little");
 
     let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
     let (reg_off, reg_top_index, slot_size) = if gr_type {
@@ -171,8 +171,8 @@
 ) -> &'ll Value {
     // Determine the va_arg implementation to use. The LLVM va_arg instruction
     // is lacking in some instances, so we should only use it as a fallback.
-    let target = &bx.cx.tcx.sess.target.target;
-    let arch = &bx.cx.tcx.sess.target.target.arch;
+    let target = &bx.cx.tcx.sess.target;
+    let arch = &bx.cx.tcx.sess.target.arch;
     match (&**arch, target.options.is_like_windows) {
         // Windows x86
         ("x86", true) => {
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index f83b4b2..ef722ec 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -9,9 +9,7 @@
     // times show up as foo.lib
     let oslibname = format!(
         "{}{}{}",
-        sess.target.target.options.staticlib_prefix,
-        name,
-        sess.target.target.options.staticlib_suffix
+        sess.target.options.staticlib_prefix, name, sess.target.options.staticlib_suffix
     );
     let unixlibname = format!("lib{}.a", name);
 
diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs
index 0208bb7..503c51d 100644
--- a/compiler/rustc_codegen_ssa/src/back/command.rs
+++ b/compiler/rustc_codegen_ssa/src/back/command.rs
@@ -111,6 +111,12 @@
                     LldFlavor::Link => "link",
                     LldFlavor::Ld64 => "darwin",
                 });
+                if let LldFlavor::Wasm = flavor {
+                    // LLVM expects host-specific formatting for @file
+                    // arguments, but we always generate posix formatted files
+                    // at this time. Indicate as such.
+                    c.arg("--rsp-quoting=posix");
+                }
                 c
             }
         };
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 87d539f..63d0a88 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -15,7 +15,7 @@
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
-use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel};
+use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target};
 
 use super::archive::ArchiveBuilder;
 use super::command::Command;
@@ -152,7 +152,7 @@
         _ => match flavor {
             LinkerFlavor::Lld(f) => Command::lld(linker, f),
             LinkerFlavor::Msvc
-                if sess.opts.cg.linker.is_none() && sess.target.target.options.linker.is_none() =>
+                if sess.opts.cg.linker.is_none() && sess.target.options.linker.is_none() =>
             {
                 Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker))
             }
@@ -163,7 +163,7 @@
     // UWP apps have API restrictions enforced during Store submissions.
     // To comply with the Windows App Certification Kit,
     // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
-    let t = &sess.target.target;
+    let t = &sess.target;
     if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
         && t.target_vendor == "uwp"
     {
@@ -197,7 +197,7 @@
     // PATH for the child.
     let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
     let mut msvc_changed_path = false;
-    if sess.target.target.options.is_like_msvc {
+    if sess.target.options.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
             cmd.args(tool.args());
             for &(ref k, ref v) in tool.env() {
@@ -365,7 +365,7 @@
             // After adding all files to the archive, we need to update the
             // symbol table of the archive. This currently dies on macOS (see
             // #11162), and isn't necessary there anyway
-            if !sess.target.target.options.is_like_osx {
+            if !sess.target.options.is_like_osx {
                 ab.update_symbols();
             }
         }
@@ -476,10 +476,10 @@
 
     linker::disable_localization(&mut cmd);
 
-    for &(ref k, ref v) in &sess.target.target.options.link_env {
+    for &(ref k, ref v) in &sess.target.options.link_env {
         cmd.env(k, v);
     }
-    for k in &sess.target.target.options.link_env_remove {
+    for k in &sess.target.options.link_env_remove {
         cmd.env_remove(k);
     }
 
@@ -515,7 +515,7 @@
         // if the linker doesn't support -no-pie then it should not default to
         // linking executables as pie. Different versions of gcc seem to use
         // different quotes in the error message so don't check for them.
-        if sess.target.target.options.linker_is_gnu
+        if sess.target.options.linker_is_gnu
             && flavor != LinkerFlavor::Ld
             && (out.contains("unrecognized command line option")
                 || out.contains("unknown argument"))
@@ -535,7 +535,7 @@
 
         // Detect '-static-pie' used with an older version of gcc or clang not supporting it.
         // Fallback from '-static-pie' to '-static' in that case.
-        if sess.target.target.options.linker_is_gnu
+        if sess.target.options.linker_is_gnu
             && flavor != LinkerFlavor::Ld
             && (out.contains("unrecognized command line option")
                 || out.contains("unknown argument"))
@@ -548,7 +548,7 @@
             );
             // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
             let self_contained = crt_objects_fallback(sess, crate_type);
-            let opts = &sess.target.target.options;
+            let opts = &sess.target.options;
             let pre_objects = if self_contained {
                 &opts.pre_link_objects_fallback
             } else {
@@ -670,7 +670,7 @@
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
                 if let Some(code) = prog.status.code() {
-                    if sess.target.target.options.is_like_msvc
+                    if sess.target.options.is_like_msvc
                         && flavor == LinkerFlavor::Msvc
                         // Respect the command line override
                         && sess.opts.cg.linker.is_none()
@@ -741,7 +741,7 @@
 
             linker_error.emit();
 
-            if sess.target.target.options.is_like_msvc && linker_not_found {
+            if sess.target.options.is_like_msvc && linker_not_found {
                 sess.note_without_error(
                     "the msvc targets depend on the msvc linker \
                      but `link.exe` was not found",
@@ -758,7 +758,7 @@
     // On macOS, debuggers need this utility to get run to do some munging of
     // the symbols. Note, though, that if the object files are being preserved
     // for their debug information there's no need for us to run dsymutil.
-    if sess.target.target.options.is_like_osx
+    if sess.target.options.is_like_osx
         && sess.opts.debuginfo != DebugInfo::None
         && !preserve_objects_for_their_debuginfo(sess)
     {
@@ -776,7 +776,7 @@
     let needs_runtime = match crate_type {
         CrateType::Executable => true,
         CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
-            sess.target.target.options.is_like_osx
+            sess.target.options.is_like_osx
         }
         CrateType::Rlib | CrateType::Staticlib => false,
     };
@@ -846,7 +846,7 @@
     // If our target enables builtin function lowering in LLVM then the
     // crates providing these functions don't participate in LTO (e.g.
     // no_builtins or compiler builtins crates).
-    !sess.target.target.options.no_builtins
+    !sess.target.options.no_builtins
         && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
 }
 
@@ -906,10 +906,10 @@
                 } else if stem == "link" || stem == "lld-link" {
                     LinkerFlavor::Msvc
                 } else if stem == "lld" || stem == "rust-lld" {
-                    LinkerFlavor::Lld(sess.target.target.options.lld_flavor)
+                    LinkerFlavor::Lld(sess.target.options.lld_flavor)
                 } else {
                     // fall back to the value in the target spec
-                    sess.target.target.linker_flavor
+                    sess.target.linker_flavor
                 };
 
                 Some((linker, flavor))
@@ -926,8 +926,8 @@
 
     if let Some(ret) = infer_from(
         sess,
-        sess.target.target.options.linker.clone().map(PathBuf::from),
-        Some(sess.target.target.linker_flavor),
+        sess.target.options.linker.clone().map(PathBuf::from),
+        Some(sess.target.linker_flavor),
     ) {
         return ret;
     }
@@ -962,7 +962,7 @@
     // Basically as a result this just means that if we're on OSX and we're
     // *not* running dsymutil then the object files are the only source of truth
     // for debug information, so we must preserve them.
-    if sess.target.target.options.is_like_osx {
+    if sess.target.options.is_like_osx {
         return !sess.opts.debugging_opts.run_dsymutil;
     }
 
@@ -988,7 +988,7 @@
                 NativeLibKind::StaticNoBundle
                 | NativeLibKind::Dylib
                 | NativeLibKind::Unspecified => {
-                    if sess.target.target.options.is_like_msvc {
+                    if sess.target.options.is_like_msvc {
                         Some(format!("{}.lib", name))
                     } else {
                         Some(format!("-l{}", name))
@@ -1070,16 +1070,13 @@
     let mut args = String::new();
     for arg in cmd2.take_args() {
         args.push_str(
-            &Escape {
-                arg: arg.to_str().unwrap(),
-                is_like_msvc: sess.target.target.options.is_like_msvc,
-            }
-            .to_string(),
+            &Escape { arg: arg.to_str().unwrap(), is_like_msvc: sess.target.options.is_like_msvc }
+                .to_string(),
         );
         args.push('\n');
     }
     let file = tmpdir.join("linker-arguments");
-    let bytes = if sess.target.target.options.is_like_msvc {
+    let bytes = if sess.target.options.is_like_msvc {
         let mut out = Vec::with_capacity((1 + args.len()) * 2);
         // start the stream with a UTF-16 BOM
         for c in std::iter::once(0xFEFF).chain(args.encode_utf16()) {
@@ -1195,7 +1192,7 @@
     };
 
     // Adjust the output kind to target capabilities.
-    let opts = &sess.target.target.options;
+    let opts = &sess.target.options;
     let pic_exe_supported = opts.position_independent_executables;
     let static_pic_exe_supported = opts.static_position_independent_executables;
     let static_dylib_supported = opts.crt_static_allows_dylibs;
@@ -1236,14 +1233,14 @@
         return self_contained;
     }
 
-    match sess.target.target.options.crt_objects_fallback {
+    match sess.target.options.crt_objects_fallback {
         // FIXME: Find a better heuristic for "native musl toolchain is available",
         // based on host and linker path, for example.
         // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
         Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)),
         Some(CrtObjectsFallback::Mingw) => {
-            sess.host == sess.target.target
-                && sess.target.target.target_vendor != "uwp"
+            sess.host == sess.target
+                && sess.target.target_vendor != "uwp"
                 && detect_self_contained_mingw(&sess)
         }
         // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
@@ -1259,7 +1256,7 @@
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
-    let opts = &sess.target.target.options;
+    let opts = &sess.target.options;
     let objects =
         if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
@@ -1274,7 +1271,7 @@
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
-    let opts = &sess.target.target.options;
+    let opts = &sess.target.options;
     let objects =
         if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
@@ -1285,7 +1282,7 @@
 /// Add arbitrary "pre-link" args defined by the target spec or from command line.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
+    if let Some(args) = sess.target.options.pre_link_args.get(&flavor) {
         cmd.args(args);
     }
     cmd.args(&sess.opts.debugging_opts.pre_link_args);
@@ -1293,13 +1290,13 @@
 
 /// Add a link script embedded in the target, if applicable.
 fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) {
-    match (crate_type, &sess.target.target.options.link_script) {
+    match (crate_type, &sess.target.options.link_script) {
         (CrateType::Cdylib | CrateType::Executable, Some(script)) => {
-            if !sess.target.target.options.linker_is_gnu {
+            if !sess.target.options.linker_is_gnu {
                 sess.fatal("can only use link script when linking with GNU-like linker");
             }
 
-            let file_name = ["rustc", &sess.target.target.llvm_target, "linkfile.ld"].join("-");
+            let file_name = ["rustc", &sess.target.llvm_target, "linkfile.ld"].join("-");
 
             let path = tmpdir.join(file_name);
             if let Err(e) = fs::write(&path, script) {
@@ -1338,15 +1335,15 @@
             *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
         });
     if any_dynamic_crate {
-        if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) {
+        if let Some(args) = sess.target.options.late_link_args_dynamic.get(&flavor) {
             cmd.args(args);
         }
     } else {
-        if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) {
+        if let Some(args) = sess.target.options.late_link_args_static.get(&flavor) {
             cmd.args(args);
         }
     }
-    if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
+    if let Some(args) = sess.target.options.late_link_args.get(&flavor) {
         cmd.args(args);
     }
 }
@@ -1354,7 +1351,7 @@
 /// Add arbitrary "post-link" args defined by the target spec.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
+    if let Some(args) = sess.target.options.post_link_args.get(&flavor) {
         cmd.args(args);
     }
 }
@@ -1456,7 +1453,7 @@
 /// Add options making relocation sections in the produced ELF files read-only
 /// and suppressing lazy binding.
 fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) {
-    match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.target.options.relro_level) {
+    match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.options.relro_level) {
         RelroLevel::Full => cmd.full_relro(),
         RelroLevel::Partial => cmd.partial_relro(),
         RelroLevel::Off => cmd.no_relro(),
@@ -1487,9 +1484,9 @@
         let mut rpath_config = RPathConfig {
             used_crates: &codegen_results.crate_info.used_crates_dynamic,
             out_filename: out_filename.to_path_buf(),
-            has_rpath: sess.target.target.options.has_rpath,
-            is_like_osx: sess.target.target.options.is_like_osx,
-            linker_is_gnu: sess.target.target.options.linker_is_gnu,
+            has_rpath: sess.target.options.has_rpath,
+            is_like_osx: sess.target.options.is_like_osx,
+            linker_is_gnu: sess.target.options.linker_is_gnu,
             get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
         };
         cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
@@ -1517,18 +1514,21 @@
     let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback);
     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
     // to the linker args construction.
-    assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp");
+    assert!(base_cmd.get_args().is_empty() || sess.target.target_vendor == "uwp");
     let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
     let link_output_kind = link_output_kind(sess, crate_type);
 
     // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
     add_pre_link_args(cmd, sess, flavor);
 
+    // NO-OPT-OUT, OBJECT-FILES-NO
+    add_apple_sdk(cmd, sess, flavor);
+
     // NO-OPT-OUT
     add_link_script(cmd, sess, tmpdir, crate_type);
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
+    if sess.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
         let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
         } else {
@@ -1538,7 +1538,7 @@
     }
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.target.options.eh_frame_header {
+    if sess.target.options.eh_frame_header {
         cmd.add_eh_frame_header();
     }
 
@@ -1551,7 +1551,7 @@
     add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.target.options.is_like_emscripten {
+    if sess.target.options.is_like_emscripten {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
             "DISABLE_EXCEPTION_CATCHING=1"
@@ -1579,7 +1579,7 @@
     cmd.output_filename(out_filename);
 
     // OBJECT-FILES-NO, AUDIT-ORDER
-    if crate_type == CrateType::Executable && sess.target.target.options.is_like_windows {
+    if crate_type == CrateType::Executable && sess.target.options.is_like_windows {
         if let Some(ref s) = codegen_results.windows_subsystem {
             cmd.subsystem(s);
         }
@@ -1623,7 +1623,7 @@
     // OBJECT-FILES-NO, AUDIT-ORDER
     // We want to prevent the compiler from accidentally leaking in any system libraries,
     // so by default we tell linkers not to link to any default libraries.
-    if !sess.opts.cg.default_linker_libraries && sess.target.target.options.no_default_libraries {
+    if !sess.opts.cg.default_linker_libraries && sess.target.options.no_default_libraries {
         cmd.no_default_libraries();
     }
 
@@ -1842,12 +1842,8 @@
     }
 
     // Converts a library file-stem into a cc -l argument
-    fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str {
-        if stem.starts_with("lib") && !config.target.options.is_like_windows {
-            &stem[3..]
-        } else {
-            stem
-        }
+    fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
+        if stem.starts_with("lib") && !target.options.is_like_windows { &stem[3..] } else { stem }
     }
 
     // Adds the static "rlib" versions of all crates to the command line.
@@ -1942,7 +1938,7 @@
                 // though, so we let that object file slide.
                 let skip_because_lto = are_upstream_rust_objects_already_included(sess)
                     && is_rust_object
-                    && (sess.target.target.options.no_builtins
+                    && (sess.target.options.no_builtins
                         || !codegen_results.crate_info.is_no_builtins.contains(&cnum));
 
                 if skip_because_cfg_say_so || skip_because_lto {
@@ -2083,3 +2079,86 @@
         config::Lto::No | config::Lto::ThinLocal => false,
     }
 }
+
+fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
+    let arch = &sess.target.arch;
+    let os = &sess.target.target_os;
+    let llvm_target = &sess.target.llvm_target;
+    if sess.target.target_vendor != "apple"
+        || !matches!(os.as_str(), "ios" | "tvos")
+        || flavor != LinkerFlavor::Gcc
+    {
+        return;
+    }
+    let sdk_name = match (arch.as_str(), os.as_str()) {
+        ("aarch64", "tvos") => "appletvos",
+        ("x86_64", "tvos") => "appletvsimulator",
+        ("arm", "ios") => "iphoneos",
+        ("aarch64", "ios") => "iphoneos",
+        ("x86", "ios") => "iphonesimulator",
+        ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx10.15",
+        ("x86_64", "ios") => "iphonesimulator",
+        _ => {
+            sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
+            return;
+        }
+    };
+    let sdk_root = match get_apple_sdk_root(sdk_name) {
+        Ok(s) => s,
+        Err(e) => {
+            sess.err(&e);
+            return;
+        }
+    };
+    let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
+    cmd.args(&["-arch", arch_name, "-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
+}
+
+fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
+    // Following what clang does
+    // (https://github.com/llvm/llvm-project/blob/
+    // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678)
+    // to allow the SDK path to be set. (For clang, xcrun sets
+    // SDKROOT; for rustc, the user or build system can set it, or we
+    // can fall back to checking for xcrun on PATH.)
+    if let Ok(sdkroot) = env::var("SDKROOT") {
+        let p = Path::new(&sdkroot);
+        match sdk_name {
+            // Ignore `SDKROOT` if it's clearly set for the wrong platform.
+            "appletvos"
+                if sdkroot.contains("TVSimulator.platform")
+                    || sdkroot.contains("MacOSX.platform") => {}
+            "appletvsimulator"
+                if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {}
+            "iphoneos"
+                if sdkroot.contains("iPhoneSimulator.platform")
+                    || sdkroot.contains("MacOSX.platform") => {}
+            "iphonesimulator"
+                if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => {
+            }
+            "macosx10.15"
+                if sdkroot.contains("iPhoneOS.platform")
+                    || sdkroot.contains("iPhoneSimulator.platform") => {}
+            // Ignore `SDKROOT` if it's not a valid path.
+            _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {}
+            _ => return Ok(sdkroot),
+        }
+    }
+    let res =
+        Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then(
+            |output| {
+                if output.status.success() {
+                    Ok(String::from_utf8(output.stdout).unwrap())
+                } else {
+                    let error = String::from_utf8(output.stderr);
+                    let error = format!("process exit with error: {}", error.unwrap());
+                    Err(io::Error::new(io::ErrorKind::Other, &error[..]))
+                }
+            },
+        );
+
+    match res {
+        Ok(output) => Ok(output.trim().to_string()),
+        Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 0ddf8bd..3e13a1d 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -184,7 +184,7 @@
         // * On OSX they have their own linker, not binutils'
         // * For WebAssembly the only functional linker is LLD, which doesn't
         //   support hint flags
-        !self.sess.target.target.options.is_like_osx && self.sess.target.target.arch != "wasm32"
+        !self.sess.target.options.is_like_osx && self.sess.target.arch != "wasm32"
     }
 
     // Some platforms take hints about whether a library is static or dynamic.
@@ -221,10 +221,8 @@
         let opt_level = match self.sess.opts.optimize {
             config::OptLevel::No => "O0",
             config::OptLevel::Less => "O1",
-            config::OptLevel::Default => "O2",
+            config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
             config::OptLevel::Aggressive => "O3",
-            config::OptLevel::Size => "Os",
-            config::OptLevel::SizeMin => "Oz",
         };
 
         self.linker_arg(&format!("-plugin-opt={}", opt_level));
@@ -234,7 +232,7 @@
 
     fn build_dylib(&mut self, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             self.cmd.arg("-dynamiclib");
             self.linker_arg("-dylib");
 
@@ -250,7 +248,7 @@
             }
         } else {
             self.cmd.arg("-shared");
-            if self.sess.target.target.options.is_like_windows {
+            if self.sess.target.options.is_like_windows {
                 // The output filename already contains `dll_suffix` so
                 // the resulting import library will have a name in the
                 // form of libfoo.dll.a
@@ -258,9 +256,9 @@
                     out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
                         format!(
                             "{}{}{}",
-                            self.sess.target.target.options.staticlib_prefix,
+                            self.sess.target.options.staticlib_prefix,
                             file,
-                            self.sess.target.target.options.staticlib_suffix
+                            self.sess.target.options.staticlib_suffix
                         )
                     });
                 if let Some(implib_name) = implib_name {
@@ -282,7 +280,7 @@
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe => {
-                if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
+                if !self.is_ld && self.sess.target.options.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -293,7 +291,7 @@
             LinkOutputKind::StaticNoPicExe => {
                 // `-static` works for both gcc wrapper and ld.
                 self.cmd.arg("-static");
-                if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
+                if !self.is_ld && self.sess.target.options.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -322,7 +320,7 @@
         // any `#[link]` attributes in the `libc` crate, see #72782 for details.
         // FIXME: Switch to using `#[link]` attributes in the `libc` crate
         // similarly to other targets.
-        if self.sess.target.target.target_os == "vxworks"
+        if self.sess.target.target_os == "vxworks"
             && matches!(
                 output_kind,
                 LinkOutputKind::StaticNoPicExe
@@ -387,7 +385,7 @@
     // functions, etc.
     fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
         self.hint_static();
-        let target = &self.sess.target.target;
+        let target = &self.sess.target;
         if !target.options.is_like_osx {
             self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
             self.linker_arg("--no-whole-archive");
@@ -402,7 +400,7 @@
 
     fn link_whole_rlib(&mut self, lib: &Path) {
         self.hint_static();
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             self.linker_arg("-force_load");
             self.linker_arg(&lib);
         } else {
@@ -426,9 +424,9 @@
         // -dead_strip can't be part of the pre_link_args because it's also used
         // for partial linking when using multiple codegen units (-r).  So we
         // insert it here.
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             self.linker_arg("-dead_strip");
-        } else if self.sess.target.target.options.is_like_solaris {
+        } else if self.sess.target.options.is_like_solaris {
             self.linker_arg("-zignore");
 
         // If we're building a dylib, we don't use --gc-sections because LLVM
@@ -442,7 +440,7 @@
     }
 
     fn optimize(&mut self) {
-        if !self.sess.target.target.options.linker_is_gnu {
+        if !self.sess.target.options.linker_is_gnu {
             return;
         }
 
@@ -456,7 +454,7 @@
     }
 
     fn pgo_gen(&mut self) {
-        if !self.sess.target.target.options.linker_is_gnu {
+        if !self.sess.target.options.linker_is_gnu {
             return;
         }
 
@@ -506,7 +504,7 @@
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
         // Symbol visibility in object files typically takes care of this.
         if crate_type == CrateType::Executable
-            && self.sess.target.target.options.override_export_symbols.is_none()
+            && self.sess.target.options.override_export_symbols.is_none()
         {
             return;
         }
@@ -515,7 +513,7 @@
         // The object files have far more public symbols than we actually want to export,
         // so we hide them all here.
 
-        if !self.sess.target.target.options.limit_rdylib_exports {
+        if !self.sess.target.options.limit_rdylib_exports {
             return;
         }
 
@@ -523,13 +521,13 @@
             return;
         }
 
-        let is_windows = self.sess.target.target.options.is_like_windows;
+        let is_windows = self.sess.target.options.is_like_windows;
         let mut arg = OsString::new();
         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
 
         debug!("EXPORTED SYMBOLS:");
 
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             // Write a plain, newline-separated list of symbols
             let res: io::Result<()> = try {
                 let mut f = BufWriter::new(File::create(&path)?);
@@ -575,12 +573,12 @@
             }
         }
 
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             if !self.is_ld {
                 arg.push("-Wl,")
             }
             arg.push("-exported_symbols_list,");
-        } else if self.sess.target.target.options.is_like_solaris {
+        } else if self.sess.target.options.is_like_solaris {
             if !self.is_ld {
                 arg.push("-Wl,")
             }
@@ -1205,7 +1203,7 @@
 }
 
 fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
-    if let Some(ref exports) = tcx.sess.target.target.options.override_export_symbols {
+    if let Some(ref exports) = tcx.sess.target.options.override_export_symbols {
         return exports.clone();
     }
 
@@ -1295,7 +1293,7 @@
         // Provide the linker with fallback to internal `target-cpu`.
         self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
             Some(ref s) => s,
-            None => &self.sess.target.target.options.cpu,
+            None => &self.sess.target.options.cpu,
         });
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 51cc1ad..dd8d751 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -229,8 +229,8 @@
         // needs to be exported.
         // However, on platforms that don't allow for Rust dylibs, having
         // external linkage is enough for monomorphization to be linked to.
-        let need_visibility = tcx.sess.target.target.options.dynamic_linking
-            && !tcx.sess.target.target.options.only_cdylib;
+        let need_visibility =
+            tcx.sess.target.options.dynamic_linking && !tcx.sess.target.options.only_cdylib;
 
         let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
 
@@ -391,7 +391,7 @@
         codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
 
     if is_extern && !std_internal {
-        let target = &tcx.sess.target.target.llvm_target;
+        let target = &tcx.sess.target.llvm_target;
         // WebAssembly cannot export data symbols, so reduce their export level
         if target.contains("emscripten") {
             if let Some(Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. })) =
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 0edf0fc..4d2cea1 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -13,7 +13,6 @@
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::profiling::TimingGuard;
 use rustc_data_structures::profiling::VerboseTimingGuard;
-use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
 use rustc_errors::{DiagnosticId, FatalError, Handler, Level};
@@ -140,7 +139,7 @@
 
         let emit_obj = if !should_emit_obj {
             EmitObj::None
-        } else if sess.target.target.options.obj_is_bitcode
+        } else if sess.target.options.obj_is_bitcode
             || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
         {
             // This case is selected if the target uses objects as bitcode, or
@@ -222,11 +221,11 @@
                 false
             ),
             emit_obj,
-            bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(),
+            bc_cmdline: sess.target.options.bitcode_llvm_cmdline.clone(),
 
             verify_llvm_ir: sess.verify_llvm_ir(),
             no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes,
-            no_builtins: no_builtins || sess.target.target.options.no_builtins,
+            no_builtins: no_builtins || sess.target.options.no_builtins,
 
             // Exclude metadata and allocator modules from time_passes output,
             // since they throw off the "LLVM passes" measurement.
@@ -253,7 +252,7 @@
                 .opts
                 .debugging_opts
                 .merge_functions
-                .unwrap_or(sess.target.target.options.merge_functions)
+                .unwrap_or(sess.target.options.merge_functions)
             {
                 MergeFunctions::Disabled => false,
                 MergeFunctions::Trampolines | MergeFunctions::Aliases => {
@@ -308,7 +307,7 @@
     pub allocator_module_config: Arc<ModuleConfig>,
     pub tm_factory: TargetMachineFactory<B>,
     pub msvc_imps_needed: bool,
-    pub target_pointer_width: String,
+    pub target_pointer_width: u32,
     pub target_arch: String,
     pub debuginfo: config::DebugInfo,
 
@@ -389,7 +388,7 @@
     let requested_for_rlib = sess.opts.cg.embed_bitcode
         && sess.crate_types().contains(&CrateType::Rlib)
         && sess.opts.output_types.contains_key(&OutputType::Exe);
-    let forced_by_target = sess.target.target.options.forces_embed_bitcode;
+    let forced_by_target = sess.target.options.forces_embed_bitcode;
     requested_for_rlib || forced_by_target
 }
 
@@ -414,7 +413,6 @@
     let sess = tcx.sess;
 
     let crate_name = tcx.crate_name(LOCAL_CRATE);
-    let crate_hash = tcx.crate_hash(LOCAL_CRATE);
     let no_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins);
     let is_compiler_builtins =
         tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins);
@@ -463,7 +461,6 @@
     OngoingCodegen {
         backend,
         crate_name,
-        crate_hash,
         metadata,
         windows_subsystem,
         linker_info,
@@ -658,15 +655,6 @@
     // These are used in linking steps and will be cleaned up afterward.
 }
 
-pub fn dump_incremental_data(_codegen_results: &CodegenResults) {
-    // FIXME(mw): This does not work at the moment because the situation has
-    //            become more complicated due to incremental LTO. Now a CGU
-    //            can have more than two caching states.
-    // println!("[incremental] Re-using {} out of {} modules",
-    //           codegen_results.modules.iter().filter(|m| m.pre_existing).count(),
-    //           codegen_results.modules.len());
-}
-
 pub enum WorkItem<B: WriteBackendMethods> {
     /// Optimize a newly codegened, totally unoptimized module.
     Optimize(ModuleCodegen<B::Module>),
@@ -1034,8 +1022,8 @@
         tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)),
         total_cgus,
         msvc_imps_needed: msvc_imps_needed(tcx),
-        target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
-        target_arch: tcx.sess.target.target.arch.clone(),
+        target_pointer_width: tcx.sess.target.pointer_width,
+        target_arch: tcx.sess.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
     };
 
@@ -1175,7 +1163,7 @@
     // necessary. There's already optimizations in place to avoid sending work
     // back to the coordinator if LTO isn't requested.
     return thread::spawn(move || {
-        let max_workers = ::num_cpus::get();
+        let max_workers = num_cpus::get();
         let mut worker_id_counter = 0;
         let mut free_worker_ids = Vec::new();
         let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
@@ -1531,8 +1519,6 @@
     }
 }
 
-pub const CODEGEN_WORKER_ID: usize = usize::MAX;
-
 /// `FatalError` is explicitly not `Send`.
 #[must_use]
 pub struct WorkerFatalError;
@@ -1720,7 +1706,6 @@
 pub struct OngoingCodegen<B: ExtraBackendMethods> {
     pub backend: B,
     pub crate_name: Symbol,
-    pub crate_hash: Svh,
     pub metadata: EncodedMetadata,
     pub windows_subsystem: Option<String>,
     pub linker_info: LinkerInfo,
@@ -1766,7 +1751,6 @@
         (
             CodegenResults {
                 crate_name: self.crate_name,
-                crate_hash: self.crate_hash,
                 metadata: self.metadata,
                 windows_subsystem: self.windows_subsystem,
                 linker_info: self.linker_info,
@@ -1881,11 +1865,11 @@
     // something is wrong with commandline arg validation.
     assert!(
         !(tcx.sess.opts.cg.linker_plugin_lto.enabled()
-            && tcx.sess.target.target.options.is_like_windows
+            && tcx.sess.target.options.is_like_windows
             && tcx.sess.opts.cg.prefer_dynamic)
     );
 
-    tcx.sess.target.target.options.is_like_windows &&
+    tcx.sess.target.options.is_like_windows &&
         tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
     // ThinLTO can't handle this workaround in all cases, so we don't
     // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index d82fc2c..4d93760 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -327,7 +327,7 @@
 /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
 /// 64-bit MinGW) instead of "full SEH".
 pub fn wants_msvc_seh(sess: &Session) -> bool {
-    sess.target.target.options.is_like_msvc
+    sess.target.options.is_like_msvc
 }
 
 pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
@@ -393,7 +393,7 @@
     ) -> Bx::Function {
         // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
         // depending on whether the target needs `argc` and `argv` to be passed in.
-        let llfty = if cx.sess().target.target.options.main_needs_argc_argv {
+        let llfty = if cx.sess().target.options.main_needs_argc_argv {
             cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
         } else {
             cx.type_func(&[], cx.type_int())
@@ -464,7 +464,7 @@
     cx: &'a Bx::CodegenCx,
     bx: &mut Bx,
 ) -> (Bx::Value, Bx::Value) {
-    if cx.sess().target.target.options.main_needs_argc_argv {
+    if cx.sess().target.options.main_needs_argc_argv {
         // Params from native `main()` used as args for rust start function
         let param_argc = bx.get_param(0);
         let param_argv = bx.get_param(1);
@@ -479,8 +479,6 @@
     }
 }
 
-pub const CODEGEN_WORKER_ID: usize = usize::MAX;
-
 pub fn codegen_crate<B: ExtraBackendMethods>(
     backend: B,
     tcx: TyCtxt<'tcx>,
@@ -538,8 +536,9 @@
         let llmod_id =
             cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
         let mut modules = backend.new_metadata(tcx, &llmod_id);
-        tcx.sess
-            .time("write_allocator_module", || backend.codegen_allocator(tcx, &mut modules, kind));
+        tcx.sess.time("write_allocator_module", || {
+            backend.codegen_allocator(tcx, &mut modules, kind, tcx.lang_items().oom().is_some())
+        });
 
         Some(ModuleCodegen { name: llmod_id, module_llvm: modules, kind: ModuleKind::Allocator })
     } else {
@@ -694,7 +693,7 @@
         total_codegen_time.into_inner(),
     );
 
-    ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+    rustc_incremental::assert_module_sources::assert_module_sources(tcx);
 
     symbol_names_test::report_symbol_names(tcx);
 
@@ -753,8 +752,8 @@
 }
 
 fn finalize_tcx(tcx: TyCtxt<'_>) {
-    tcx.sess.time("assert_dep_graph", || ::rustc_incremental::assert_dep_graph(tcx));
-    tcx.sess.time("serialize_dep_graph", || ::rustc_incremental::save_dep_graph(tcx));
+    tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
+    tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
 
     // We assume that no queries are run past here. If there are new queries
     // after this point, they'll show up as "<unknown>" in self-profiling data.
diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
index 814e43c..d8bde8e 100644
--- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
+++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
@@ -143,7 +143,9 @@
         let id_to_counter =
             |new_indexes: &IndexVec<InjectedExpressionIndex, MappedExpressionIndex>,
              id: ExpressionOperandId| {
-                if id.index() < self.counters.len() {
+                if id == ExpressionOperandId::ZERO {
+                    Some(Counter::zero())
+                } else if id.index() < self.counters.len() {
                     let index = CounterValueReference::from(id.index());
                     self.counters
                         .get(index)
@@ -179,14 +181,19 @@
                 // been assigned a `new_index`.
                 let mapped_expression_index =
                     MappedExpressionIndex::from(counter_expressions.len());
-                counter_expressions.push(CounterExpression::new(
+                let expression = CounterExpression::new(
                     lhs_counter,
                     match op {
                         Op::Add => ExprKind::Add,
                         Op::Subtract => ExprKind::Subtract,
                     },
                     rhs_counter,
-                ));
+                );
+                debug!(
+                    "Adding expression {:?} = {:?} at {:?}",
+                    mapped_expression_index, expression, region
+                );
+                counter_expressions.push(expression);
                 new_indexes[original_index] = mapped_expression_index;
                 expression_regions.push((Counter::expression(mapped_expression_index), region));
             }
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 45ecb79..c4c51d1 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -33,7 +33,7 @@
 ) {
     // When targeting MSVC, emit C++ style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let cpp_like_names = tcx.sess.target.target.options.is_like_msvc;
+    let cpp_like_names = tcx.sess.target.options.is_like_msvc;
 
     match *t.kind() {
         ty::Bool => output.push_str("bool"),
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index d4f3bf3..70b92b2 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -21,7 +21,6 @@
 extern crate rustc_middle;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::LangItem;
@@ -42,6 +41,7 @@
 pub mod meth;
 pub mod mir;
 pub mod mono_item;
+pub mod target_features;
 pub mod traits;
 
 pub struct ModuleCodegen<M> {
@@ -133,7 +133,6 @@
     pub modules: Vec<CompiledModule>,
     pub allocator_module: Option<CompiledModule>,
     pub metadata_module: Option<CompiledModule>,
-    pub crate_hash: Svh,
     pub metadata: rustc_middle::middle::cstore::EncodedMetadata,
     pub windows_subsystem: Option<String>,
     pub linker_info: back::linker::LinkerInfo,
@@ -143,6 +142,7 @@
 pub fn provide(providers: &mut Providers) {
     crate::back::symbol_export::provide(providers);
     crate::base::provide_both(providers);
+    crate::target_features::provide(providers);
 }
 
 pub fn provide_extern(providers: &mut Providers) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 703a17b..bec0a84 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -12,9 +12,9 @@
 use rustc_ast as ast;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::AssertKind;
+use rustc_middle::mir::{self, SwitchTargets};
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
@@ -24,8 +24,6 @@
 use rustc_target::abi::{self, LayoutOf};
 use rustc_target::spec::abi::Abi;
 
-use std::borrow::Cow;
-
 /// Used by `FunctionCx::codegen_terminator` for emitting common patterns
 /// e.g., creating a basic block, calling a function, etc.
 struct TerminatorCodegenHelper<'tcx> {
@@ -165,7 +163,7 @@
                 target <= self.bb
                     && target.start_location().is_predecessor_of(self.bb.start_location(), mir)
             }) {
-                bx.sideeffect();
+                bx.sideeffect(false);
             }
         }
     }
@@ -198,42 +196,37 @@
         mut bx: Bx,
         discr: &mir::Operand<'tcx>,
         switch_ty: Ty<'tcx>,
-        values: &Cow<'tcx, [u128]>,
-        targets: &Vec<mir::BasicBlock>,
+        targets: &SwitchTargets,
     ) {
         let discr = self.codegen_operand(&mut bx, &discr);
         // `switch_ty` is redundant, sanity-check that.
         assert_eq!(discr.layout.ty, switch_ty);
-        if targets.len() == 2 {
-            // If there are two targets, emit br instead of switch
-            let lltrue = helper.llblock(self, targets[0]);
-            let llfalse = helper.llblock(self, targets[1]);
+        helper.maybe_sideeffect(self.mir, &mut bx, targets.all_targets());
+
+        let mut target_iter = targets.iter();
+        if target_iter.len() == 1 {
+            // If there are two targets (one conditional, one fallback), emit br instead of switch
+            let (test_value, target) = target_iter.next().unwrap();
+            let lltrue = helper.llblock(self, target);
+            let llfalse = helper.llblock(self, targets.otherwise());
             if switch_ty == bx.tcx().types.bool {
-                helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
                 // Don't generate trivial icmps when switching on bool
-                if let [0] = values[..] {
-                    bx.cond_br(discr.immediate(), llfalse, lltrue);
-                } else {
-                    assert_eq!(&values[..], &[1]);
-                    bx.cond_br(discr.immediate(), lltrue, llfalse);
+                match test_value {
+                    0 => bx.cond_br(discr.immediate(), llfalse, lltrue),
+                    1 => bx.cond_br(discr.immediate(), lltrue, llfalse),
+                    _ => bug!(),
                 }
             } else {
                 let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
-                let llval = bx.const_uint_big(switch_llty, values[0]);
+                let llval = bx.const_uint_big(switch_llty, test_value);
                 let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
-                helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
                 bx.cond_br(cmp, lltrue, llfalse);
             }
         } else {
-            helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
-            let (otherwise, targets) = targets.split_last().unwrap();
             bx.switch(
                 discr.immediate(),
-                helper.llblock(self, *otherwise),
-                values
-                    .iter()
-                    .zip(targets)
-                    .map(|(&value, target)| (value, helper.llblock(self, *target))),
+                helper.llblock(self, targets.otherwise()),
+                target_iter.map(|(value, target)| (value, helper.llblock(self, target))),
             );
         }
     }
@@ -879,7 +872,7 @@
                         let string = match ty.kind() {
                             ty::Uint(_) => value.to_string(),
                             ty::Int(int_ty) => {
-                                match int_ty.normalize(bx.tcx().sess.target.ptr_width) {
+                                match int_ty.normalize(bx.tcx().sess.target.pointer_width) {
                                     ast::IntTy::I8 => (value as i8).to_string(),
                                     ast::IntTy::I16 => (value as i16).to_string(),
                                     ast::IntTy::I32 => (value as i32).to_string(),
@@ -971,12 +964,28 @@
             }
 
             mir::TerminatorKind::Goto { target } => {
-                helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+                if bb == target {
+                    // This is an unconditional branch back to this same basic
+                    // block. That means we have something like a `loop {}`
+                    // statement. Currently LLVM miscompiles this because it
+                    // assumes forward progress. We want to prevent this in all
+                    // cases, but that has a fairly high cost to compile times
+                    // currently. Instead, try to handle this specific case
+                    // which comes up commonly in practice (e.g., in embedded
+                    // code).
+                    //
+                    // The `true` here means we insert side effects regardless
+                    // of -Zinsert-sideeffect being passed on unconditional
+                    // branching to the same basic block.
+                    bx.sideeffect(true);
+                } else {
+                    helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
+                }
                 helper.funclet_br(self, &mut bx, target);
             }
 
-            mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
-                self.codegen_switchint_terminator(helper, bx, discr, switch_ty, values, targets);
+            mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
+                self.codegen_switchint_terminator(helper, bx, discr, switch_ty, targets);
             }
 
             mir::TerminatorKind::Return => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index d8a530d..26a646b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -55,6 +55,7 @@
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
         let (scope, span) = self.debug_loc(source_info);
+        bx.set_span(span);
         if let Some(scope) = scope {
             bx.set_source_location(scope, span);
         }
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 14f1ed5..2bf1ee4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -580,8 +580,12 @@
 // stuffs.
 fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
     match ty.kind() {
-        ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)),
-        ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)),
+        ty::Int(t) => {
+            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true))
+        }
+        ty::Uint(t) => {
+            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false))
+        }
         _ => None,
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 64d456f..bff2635 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -153,7 +153,7 @@
         bx.set_personality_fn(cx.eh_personality());
     }
 
-    bx.sideeffect();
+    bx.sideeffect(false);
 
     let cleanup_kinds = analyze::cleanup_kinds(&mir);
     // Allocate a `Block` for every basic block, except
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 91609b2..e1cc026 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -346,8 +346,8 @@
                 ..
             } => {
                 if variant_index != dataful_variant {
-                    if bx.cx().sess().target.target.arch == "arm"
-                        || bx.cx().sess().target.target.arch == "aarch64"
+                    if bx.cx().sess().target.arch == "arm"
+                        || bx.cx().sess().target.arch == "aarch64"
                     {
                         // FIXME(#34427): as workaround for LLVM bug on ARM,
                         // use memset of 0 before assigning niche value.
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
new file mode 100644
index 0000000..a8d88a9
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -0,0 +1,165 @@
+use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_middle::ty::query::Providers;
+use rustc_session::Session;
+use rustc_span::symbol::sym;
+use rustc_span::symbol::Symbol;
+
+const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("aclass", Some(sym::arm_target_feature)),
+    ("mclass", Some(sym::arm_target_feature)),
+    ("rclass", Some(sym::arm_target_feature)),
+    ("dsp", Some(sym::arm_target_feature)),
+    ("neon", Some(sym::arm_target_feature)),
+    ("crc", Some(sym::arm_target_feature)),
+    ("crypto", Some(sym::arm_target_feature)),
+    ("v5te", Some(sym::arm_target_feature)),
+    ("v6", Some(sym::arm_target_feature)),
+    ("v6k", Some(sym::arm_target_feature)),
+    ("v6t2", Some(sym::arm_target_feature)),
+    ("v7", Some(sym::arm_target_feature)),
+    ("v8", Some(sym::arm_target_feature)),
+    ("vfp2", Some(sym::arm_target_feature)),
+    ("vfp3", Some(sym::arm_target_feature)),
+    ("vfp4", Some(sym::arm_target_feature)),
+    // This is needed for inline assembly, but shouldn't be stabilized as-is
+    // since it should be enabled per-function using #[instruction_set], not
+    // #[target_feature].
+    ("thumb-mode", Some(sym::arm_target_feature)),
+];
+
+const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("fp", Some(sym::aarch64_target_feature)),
+    ("neon", Some(sym::aarch64_target_feature)),
+    ("sve", Some(sym::aarch64_target_feature)),
+    ("crc", Some(sym::aarch64_target_feature)),
+    ("crypto", Some(sym::aarch64_target_feature)),
+    ("ras", Some(sym::aarch64_target_feature)),
+    ("lse", Some(sym::aarch64_target_feature)),
+    ("rdm", Some(sym::aarch64_target_feature)),
+    ("fp16", Some(sym::aarch64_target_feature)),
+    ("rcpc", Some(sym::aarch64_target_feature)),
+    ("dotprod", Some(sym::aarch64_target_feature)),
+    ("tme", Some(sym::aarch64_target_feature)),
+    ("v8.1a", Some(sym::aarch64_target_feature)),
+    ("v8.2a", Some(sym::aarch64_target_feature)),
+    ("v8.3a", Some(sym::aarch64_target_feature)),
+];
+
+const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("adx", Some(sym::adx_target_feature)),
+    ("aes", None),
+    ("avx", None),
+    ("avx2", None),
+    ("avx512bw", Some(sym::avx512_target_feature)),
+    ("avx512cd", Some(sym::avx512_target_feature)),
+    ("avx512dq", Some(sym::avx512_target_feature)),
+    ("avx512er", Some(sym::avx512_target_feature)),
+    ("avx512f", Some(sym::avx512_target_feature)),
+    ("avx512ifma", Some(sym::avx512_target_feature)),
+    ("avx512pf", Some(sym::avx512_target_feature)),
+    ("avx512vbmi", Some(sym::avx512_target_feature)),
+    ("avx512vl", Some(sym::avx512_target_feature)),
+    ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
+    ("bmi1", None),
+    ("bmi2", None),
+    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
+    ("f16c", Some(sym::f16c_target_feature)),
+    ("fma", None),
+    ("fxsr", None),
+    ("lzcnt", None),
+    ("movbe", Some(sym::movbe_target_feature)),
+    ("pclmulqdq", None),
+    ("popcnt", None),
+    ("rdrand", None),
+    ("rdseed", None),
+    ("rtm", Some(sym::rtm_target_feature)),
+    ("sha", None),
+    ("sse", None),
+    ("sse2", None),
+    ("sse3", None),
+    ("sse4.1", None),
+    ("sse4.2", None),
+    ("sse4a", Some(sym::sse4a_target_feature)),
+    ("ssse3", None),
+    ("tbm", Some(sym::tbm_target_feature)),
+    ("xsave", None),
+    ("xsavec", None),
+    ("xsaveopt", None),
+    ("xsaves", None),
+];
+
+const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("hvx", Some(sym::hexagon_target_feature)),
+    ("hvx-length128b", Some(sym::hexagon_target_feature)),
+];
+
+const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("altivec", Some(sym::powerpc_target_feature)),
+    ("power8-altivec", Some(sym::powerpc_target_feature)),
+    ("power9-altivec", Some(sym::powerpc_target_feature)),
+    ("power8-vector", Some(sym::powerpc_target_feature)),
+    ("power9-vector", Some(sym::powerpc_target_feature)),
+    ("vsx", Some(sym::powerpc_target_feature)),
+];
+
+const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
+    &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];
+
+const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("m", Some(sym::riscv_target_feature)),
+    ("a", Some(sym::riscv_target_feature)),
+    ("c", Some(sym::riscv_target_feature)),
+    ("f", Some(sym::riscv_target_feature)),
+    ("d", Some(sym::riscv_target_feature)),
+    ("e", Some(sym::riscv_target_feature)),
+];
+
+const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
+    ("simd128", Some(sym::wasm_target_feature)),
+    ("atomics", Some(sym::wasm_target_feature)),
+    ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
+];
+
+/// When rustdoc is running, provide a list of all known features so that all their respective
+/// primitives may be documented.
+///
+/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
+pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
+    std::iter::empty()
+        .chain(ARM_ALLOWED_FEATURES.iter())
+        .chain(AARCH64_ALLOWED_FEATURES.iter())
+        .chain(X86_ALLOWED_FEATURES.iter())
+        .chain(HEXAGON_ALLOWED_FEATURES.iter())
+        .chain(POWERPC_ALLOWED_FEATURES.iter())
+        .chain(MIPS_ALLOWED_FEATURES.iter())
+        .chain(RISCV_ALLOWED_FEATURES.iter())
+        .chain(WASM_ALLOWED_FEATURES.iter())
+        .cloned()
+}
+
+pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
+    match &*sess.target.arch {
+        "arm" => ARM_ALLOWED_FEATURES,
+        "aarch64" => AARCH64_ALLOWED_FEATURES,
+        "x86" | "x86_64" => X86_ALLOWED_FEATURES,
+        "hexagon" => HEXAGON_ALLOWED_FEATURES,
+        "mips" | "mips64" => MIPS_ALLOWED_FEATURES,
+        "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
+        "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
+        "wasm32" => WASM_ALLOWED_FEATURES,
+        _ => &[],
+    }
+}
+
+pub(crate) fn provide(providers: &mut Providers) {
+    providers.supported_target_features = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        if tcx.sess.opts.actually_rustdoc {
+            // rustdoc needs to be able to document functions that use all the features, so
+            // whitelist them all
+            all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
+        } else {
+            supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
+        }
+    };
+}
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 90520f7..3fb189e 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -1,10 +1,11 @@
 use super::write::WriteBackendMethods;
 use super::CodegenObject;
-use crate::ModuleCodegen;
+use crate::{CodegenResults, ModuleCodegen};
 
 use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorReported;
-use rustc_middle::dep_graph::DepGraph;
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
 use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::query::Providers;
@@ -80,8 +81,7 @@
         &self,
         ongoing_codegen: Box<dyn Any>,
         sess: &Session,
-        dep_graph: &DepGraph,
-    ) -> Result<Box<dyn Any>, ErrorReported>;
+    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported>;
 
     /// This is called on the returned `Box<dyn Any>` from `join_codegen`
     ///
@@ -91,7 +91,7 @@
     fn link(
         &self,
         sess: &Session,
-        codegen_results: Box<dyn Any>,
+        codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported>;
 }
@@ -109,6 +109,7 @@
         tcx: TyCtxt<'tcx>,
         mods: &mut Self::Module,
         kind: AllocatorKind,
+        has_alloc_error_handler: bool,
     );
     /// This generates the codegen unit and returns it along with
     /// a `u64` giving an estimate of the unit's processing cost.
@@ -123,4 +124,5 @@
         opt_level: config::OptLevel,
     ) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>;
     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
+    fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index b35b0f2..d5bd278 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -15,6 +15,7 @@
 
 use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
 use rustc_middle::ty::Ty;
+use rustc_span::Span;
 use rustc_target::abi::{Abi, Align, Scalar, Size};
 use rustc_target::spec::HasTargetSpec;
 
@@ -44,6 +45,7 @@
     fn build_sibling_block(&self, name: &str) -> Self;
     fn cx(&self) -> &Self::CodegenCx;
     fn llbb(&self) -> Self::BasicBlock;
+    fn set_span(&mut self, span: Span);
 
     fn position_at_end(&mut self, llbb: Self::BasicBlock);
     fn ret_void(&mut self);
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index ccd294d..ac3c99f 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -20,7 +20,9 @@
     fn abort(&mut self);
     fn assume(&mut self, val: Self::Value);
     fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
-    fn sideeffect(&mut self);
+    /// Normally, sideeffect is only emitted if -Zinsert-sideeffect is passed;
+    /// in some cases though we want to emit it regardless.
+    fn sideeffect(&mut self, unconditional: bool);
     /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
     /// Rust defined C-variadic functions.
     fn va_start(&mut self, val: Self::Value) -> Self::Value;
diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 698ef60..82518b7 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -85,7 +85,7 @@
 }
 
 pub trait HasCodegen<'tcx>:
-    Backend<'tcx> + ::std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx>
+    Backend<'tcx> + std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx>
 {
     type CodegenCx: CodegenMethods<'tcx>
         + BackendTypes<
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index cec07b9..43bc0c8 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -51,7 +51,7 @@
     }
 
     fn type_int(&self) -> Self::Type {
-        match &self.sess().target.target.target_c_int_width[..] {
+        match &self.sess().target.target_c_int_width[..] {
             "16" => self.type_i16(),
             "32" => self.type_i32(),
             "64" => self.type_i64(),
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index aba0bbb..ec2f959 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -71,8 +71,8 @@
     }
 }
 
-impl ::std::fmt::Display for Fingerprint {
-    fn fmt(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+impl std::fmt::Display for Fingerprint {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(formatter, "{:x}-{:x}", self.0, self.1)
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 438a0d0..1cfbce2 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -9,6 +9,7 @@
 use super::ControlFlowGraph;
 use rustc_index::vec::{Idx, IndexVec};
 use std::borrow::BorrowMut;
+use std::cmp::Ordering;
 
 #[cfg(test)]
 mod tests;
@@ -108,6 +109,14 @@
         // FIXME -- could be optimized by using post-order-rank
         self.dominators(node).any(|n| n == dom)
     }
+
+    /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
+    /// relationship, the dominator will always precede the dominated. (The relative ordering
+    /// of two unrelated nodes will also be consistent, but otherwise the order has no
+    /// meaning.) This method cannot be used to determine if either Node dominates the other.
+    pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
+        self.post_order_rank[lhs].partial_cmp(&self.post_order_rank[rhs])
+    }
 }
 
 pub struct Iter<'dom, Node: Idx> {
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 90b0f25..9958e5d 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -100,8 +100,7 @@
 pub mod work_queue;
 pub use atomic_ref::AtomicRef;
 pub mod frozen;
-pub mod mini_map;
-pub mod mini_set;
+pub mod sso;
 pub mod tagged_ptr;
 pub mod temp_dir;
 pub mod unhash;
diff --git a/compiler/rustc_data_structures/src/mini_map.rs b/compiler/rustc_data_structures/src/mini_map.rs
deleted file mode 100644
index cd3e949..0000000
--- a/compiler/rustc_data_structures/src/mini_map.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use crate::fx::FxHashMap;
-use arrayvec::ArrayVec;
-
-use std::hash::Hash;
-
-/// Small-storage-optimized implementation of a map
-/// made specifically for caching results.
-///
-/// Stores elements in a small array up to a certain length
-/// and switches to `HashMap` when that length is exceeded.
-pub enum MiniMap<K, V> {
-    Array(ArrayVec<[(K, V); 8]>),
-    Map(FxHashMap<K, V>),
-}
-
-impl<K: Eq + Hash, V> MiniMap<K, V> {
-    /// Creates an empty `MiniMap`.
-    pub fn new() -> Self {
-        MiniMap::Array(ArrayVec::new())
-    }
-
-    /// Inserts or updates value in the map.
-    pub fn insert(&mut self, key: K, value: V) {
-        match self {
-            MiniMap::Array(array) => {
-                for pair in array.iter_mut() {
-                    if pair.0 == key {
-                        pair.1 = value;
-                        return;
-                    }
-                }
-                if let Err(error) = array.try_push((key, value)) {
-                    let mut map: FxHashMap<K, V> = array.drain(..).collect();
-                    let (key, value) = error.element();
-                    map.insert(key, value);
-                    *self = MiniMap::Map(map);
-                }
-            }
-            MiniMap::Map(map) => {
-                map.insert(key, value);
-            }
-        }
-    }
-
-    /// Return value by key if any.
-    pub fn get(&self, key: &K) -> Option<&V> {
-        match self {
-            MiniMap::Array(array) => {
-                for pair in array {
-                    if pair.0 == *key {
-                        return Some(&pair.1);
-                    }
-                }
-                return None;
-            }
-            MiniMap::Map(map) => {
-                return map.get(key);
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_data_structures/src/mini_set.rs b/compiler/rustc_data_structures/src/mini_set.rs
deleted file mode 100644
index 9d45af7..0000000
--- a/compiler/rustc_data_structures/src/mini_set.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use crate::fx::FxHashSet;
-use arrayvec::ArrayVec;
-use std::hash::Hash;
-/// Small-storage-optimized implementation of a set.
-///
-/// Stores elements in a small array up to a certain length
-/// and switches to `HashSet` when that length is exceeded.
-pub enum MiniSet<T> {
-    Array(ArrayVec<[T; 8]>),
-    Set(FxHashSet<T>),
-}
-
-impl<T: Eq + Hash> MiniSet<T> {
-    /// Creates an empty `MiniSet`.
-    pub fn new() -> Self {
-        MiniSet::Array(ArrayVec::new())
-    }
-
-    /// Adds a value to the set.
-    ///
-    /// If the set did not have this value present, true is returned.
-    ///
-    /// If the set did have this value present, false is returned.
-    pub fn insert(&mut self, elem: T) -> bool {
-        match self {
-            MiniSet::Array(array) => {
-                if array.iter().any(|e| *e == elem) {
-                    false
-                } else {
-                    if let Err(error) = array.try_push(elem) {
-                        let mut set: FxHashSet<T> = array.drain(..).collect();
-                        set.insert(error.element());
-                        *self = MiniSet::Set(set);
-                    }
-                    true
-                }
-            }
-            MiniSet::Set(set) => set.insert(elem),
-        }
-    }
-}
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 7cf5202..a5b2df1 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -129,7 +129,7 @@
 struct ObligationTreeId(usize);
 
 type ObligationTreeIdGenerator =
-    ::std::iter::Map<::std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
+    std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
 
 pub struct ObligationForest<O: ForestObligation> {
     /// The list of obligations. In between calls to `process_obligations`,
@@ -149,8 +149,8 @@
     /// comments in `process_obligation` for details.
     active_cache: FxHashMap<O::CacheKey, usize>,
 
-    /// A vector reused in compress(), to avoid allocating new vectors.
-    node_rewrites: Vec<usize>,
+    /// A vector reused in compress() and find_cycles_from_node(), to avoid allocating new vectors.
+    reused_node_vec: Vec<usize>,
 
     obligation_tree_id_generator: ObligationTreeIdGenerator,
 
@@ -251,12 +251,22 @@
     Error,
 }
 
+/// This trait allows us to have two different Outcome types:
+///  - the normal one that does as little as possible
+///  - one for tests that does some additional work and checking
+pub trait OutcomeTrait {
+    type Error;
+    type Obligation;
+
+    fn new() -> Self;
+    fn mark_not_stalled(&mut self);
+    fn is_stalled(&self) -> bool;
+    fn record_completed(&mut self, outcome: &Self::Obligation);
+    fn record_error(&mut self, error: Self::Error);
+}
+
 #[derive(Debug)]
 pub struct Outcome<O, E> {
-    /// Obligations that were completely evaluated, including all
-    /// (transitive) subobligations. Only computed if requested.
-    pub completed: Option<Vec<O>>,
-
     /// Backtrace of obligations that were found to be in error.
     pub errors: Vec<Error<O, E>>,
 
@@ -269,12 +279,29 @@
     pub stalled: bool,
 }
 
-/// Should `process_obligations` compute the `Outcome::completed` field of its
-/// result?
-#[derive(PartialEq)]
-pub enum DoCompleted {
-    No,
-    Yes,
+impl<O, E> OutcomeTrait for Outcome<O, E> {
+    type Error = Error<O, E>;
+    type Obligation = O;
+
+    fn new() -> Self {
+        Self { stalled: true, errors: vec![] }
+    }
+
+    fn mark_not_stalled(&mut self) {
+        self.stalled = false;
+    }
+
+    fn is_stalled(&self) -> bool {
+        self.stalled
+    }
+
+    fn record_completed(&mut self, _outcome: &Self::Obligation) {
+        // do nothing
+    }
+
+    fn record_error(&mut self, error: Self::Error) {
+        self.errors.push(error)
+    }
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -289,7 +316,7 @@
             nodes: vec![],
             done_cache: Default::default(),
             active_cache: Default::default(),
-            node_rewrites: vec![],
+            reused_node_vec: vec![],
             obligation_tree_id_generator: (0..).map(ObligationTreeId),
             error_cache: Default::default(),
         }
@@ -363,8 +390,7 @@
             .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
             .collect();
 
-        let successful_obligations = self.compress(DoCompleted::Yes);
-        assert!(successful_obligations.unwrap().is_empty());
+        self.compress(|_| assert!(false));
         errors
     }
 
@@ -392,16 +418,12 @@
     /// be called in a loop until `outcome.stalled` is false.
     ///
     /// This _cannot_ be unrolled (presently, at least).
-    pub fn process_obligations<P>(
-        &mut self,
-        processor: &mut P,
-        do_completed: DoCompleted,
-    ) -> Outcome<O, P::Error>
+    pub fn process_obligations<P, OUT>(&mut self, processor: &mut P) -> OUT
     where
         P: ObligationProcessor<Obligation = O>,
+        OUT: OutcomeTrait<Obligation = O, Error = Error<O, P::Error>>,
     {
-        let mut errors = vec![];
-        let mut stalled = true;
+        let mut outcome = OUT::new();
 
         // Note that the loop body can append new nodes, and those new nodes
         // will then be processed by subsequent iterations of the loop.
@@ -429,7 +451,7 @@
                 }
                 ProcessResult::Changed(children) => {
                     // We are not (yet) stalled.
-                    stalled = false;
+                    outcome.mark_not_stalled();
                     node.state.set(NodeState::Success);
 
                     for child in children {
@@ -442,28 +464,22 @@
                     }
                 }
                 ProcessResult::Error(err) => {
-                    stalled = false;
-                    errors.push(Error { error: err, backtrace: self.error_at(index) });
+                    outcome.mark_not_stalled();
+                    outcome.record_error(Error { error: err, backtrace: self.error_at(index) });
                 }
             }
             index += 1;
         }
 
-        if stalled {
-            // There's no need to perform marking, cycle processing and compression when nothing
-            // changed.
-            return Outcome {
-                completed: if do_completed == DoCompleted::Yes { Some(vec![]) } else { None },
-                errors,
-                stalled,
-            };
+        // There's no need to perform marking, cycle processing and compression when nothing
+        // changed.
+        if !outcome.is_stalled() {
+            self.mark_successes();
+            self.process_cycles(processor);
+            self.compress(|obl| outcome.record_completed(obl));
         }
 
-        self.mark_successes();
-        self.process_cycles(processor);
-        let completed = self.compress(do_completed);
-
-        Outcome { completed, errors, stalled }
+        outcome
     }
 
     /// Returns a vector of obligations for `p` and all of its
@@ -526,7 +542,6 @@
             let node = &self.nodes[index];
             let state = node.state.get();
             if state == NodeState::Success {
-                node.state.set(NodeState::Waiting);
                 // This call site is cold.
                 self.uninlined_mark_dependents_as_waiting(node);
             } else {
@@ -538,17 +553,18 @@
     // This never-inlined function is for the cold call site.
     #[inline(never)]
     fn uninlined_mark_dependents_as_waiting(&self, node: &Node<O>) {
+        // Mark node Waiting in the cold uninlined code instead of the hot inlined
+        node.state.set(NodeState::Waiting);
         self.inlined_mark_dependents_as_waiting(node)
     }
 
     /// Report cycles between all `Success` nodes, and convert all `Success`
     /// nodes to `Done`. This must be called after `mark_successes`.
-    fn process_cycles<P>(&self, processor: &mut P)
+    fn process_cycles<P>(&mut self, processor: &mut P)
     where
         P: ObligationProcessor<Obligation = O>,
     {
-        let mut stack = vec![];
-
+        let mut stack = std::mem::take(&mut self.reused_node_vec);
         for (index, node) in self.nodes.iter().enumerate() {
             // For some benchmarks this state test is extremely hot. It's a win
             // to handle the no-op cases immediately to avoid the cost of the
@@ -559,6 +575,7 @@
         }
 
         debug_assert!(stack.is_empty());
+        self.reused_node_vec = stack;
     }
 
     fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize)
@@ -591,13 +608,12 @@
     /// indices and hence invalidates any outstanding indices. `process_cycles`
     /// must be run beforehand to remove any cycles on `Success` nodes.
     #[inline(never)]
-    fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
+    fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
         let orig_nodes_len = self.nodes.len();
-        let mut node_rewrites: Vec<_> = std::mem::take(&mut self.node_rewrites);
+        let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec);
         debug_assert!(node_rewrites.is_empty());
         node_rewrites.extend(0..orig_nodes_len);
         let mut dead_nodes = 0;
-        let mut removed_done_obligations: Vec<O> = vec![];
 
         // Move removable nodes to the end, preserving the order of the
         // remaining nodes.
@@ -627,10 +643,8 @@
                     } else {
                         self.done_cache.insert(node.obligation.as_cache_key().clone());
                     }
-                    if do_completed == DoCompleted::Yes {
-                        // Extract the success stories.
-                        removed_done_obligations.push(node.obligation.clone());
-                    }
+                    // Extract the success stories.
+                    outcome_cb(&node.obligation);
                     node_rewrites[index] = orig_nodes_len;
                     dead_nodes += 1;
                 }
@@ -654,9 +668,7 @@
         }
 
         node_rewrites.truncate(0);
-        self.node_rewrites = node_rewrites;
-
-        if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None }
+        self.reused_node_vec = node_rewrites;
     }
 
     fn apply_rewrites(&mut self, node_rewrites: &[usize]) {
diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
index 0165246..371c62c 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
@@ -17,6 +17,40 @@
     marker: PhantomData<(O, E)>,
 }
 
+struct TestOutcome<O, E> {
+    pub completed: Vec<O>,
+    pub errors: Vec<Error<O, E>>,
+    pub stalled: bool,
+}
+
+impl<O, E> OutcomeTrait for TestOutcome<O, E>
+where
+    O: Clone,
+{
+    type Error = Error<O, E>;
+    type Obligation = O;
+
+    fn new() -> Self {
+        Self { errors: vec![], stalled: false, completed: vec![] }
+    }
+
+    fn mark_not_stalled(&mut self) {
+        self.stalled = false;
+    }
+
+    fn is_stalled(&self) -> bool {
+        self.stalled
+    }
+
+    fn record_completed(&mut self, outcome: &Self::Obligation) {
+        self.completed.push(outcome.clone())
+    }
+
+    fn record_error(&mut self, error: Self::Error) {
+        self.errors.push(error)
+    }
+}
+
 #[allow(non_snake_case)]
 fn C<OF, BF, O>(of: OF, bf: BF) -> ClosureObligationProcessor<OF, BF, O, &'static str>
 where
@@ -65,20 +99,17 @@
     //      A |-> A.1
     //        |-> A.2
     //        |-> A.3
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
-                "B" => ProcessResult::Error("B is for broken"),
-                "C" => ProcessResult::Changed(vec![]),
-                "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap(), vec!["C"]);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
+            "B" => ProcessResult::Error("B is for broken"),
+            "C" => ProcessResult::Changed(vec![]),
+            "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok, vec!["C"]);
     assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]);
 
     // second round: two delays, one success, creating an uneven set of subtasks:
@@ -88,60 +119,51 @@
     //      D |-> D.1
     //        |-> D.2
     forest.register_obligation("D");
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A.1" => ProcessResult::Unchanged,
-                "A.2" => ProcessResult::Unchanged,
-                "A.3" => ProcessResult::Changed(vec!["A.3.i"]),
-                "D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
-                "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A.1" => ProcessResult::Unchanged,
+            "A.2" => ProcessResult::Unchanged,
+            "A.3" => ProcessResult::Changed(vec!["A.3.i"]),
+            "D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
+            "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok, Vec::<&'static str>::new());
     assert_eq!(err, Vec::new());
 
     // third round: ok in A.1 but trigger an error in A.2. Check that it
     // propagates to A, but not D.1 or D.2.
     //      D |-> D.1 |-> D.1.i
     //        |-> D.2 |-> D.2.i
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A.1" => ProcessResult::Changed(vec![]),
-                "A.2" => ProcessResult::Error("A is for apple"),
-                "A.3.i" => ProcessResult::Changed(vec![]),
-                "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
-                "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
-                "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    let mut ok = ok.unwrap();
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A.1" => ProcessResult::Changed(vec![]),
+            "A.2" => ProcessResult::Error("A is for apple"),
+            "A.3.i" => ProcessResult::Changed(vec![]),
+            "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
+            "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
+            "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    let mut ok = ok;
     ok.sort();
     assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
     assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]);
 
     // fourth round: error in D.1.i
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "D.1.i" => ProcessResult::Error("D is for dumb"),
-                "D.2.i" => ProcessResult::Changed(vec![]),
-                _ => panic!("unexpected obligation {:?}", obligation),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    let mut ok = ok.unwrap();
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "D.1.i" => ProcessResult::Error("D is for dumb"),
+            "D.2.i" => ProcessResult::Changed(vec![]),
+            _ => panic!("unexpected obligation {:?}", obligation),
+        },
+        |_| {},
+    ));
+    let mut ok = ok;
     ok.sort();
     assert_eq!(ok, vec!["D.2", "D.2.i"]);
     assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]);
@@ -160,72 +182,60 @@
     let mut forest = ObligationForest::new();
     forest.register_obligation("A");
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
-                "A.1" => ProcessResult::Changed(vec![]),
-                "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
-                "A.3" => ProcessResult::Changed(vec![]),
-                "A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    let mut ok = ok.unwrap();
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
+            "A.1" => ProcessResult::Changed(vec![]),
+            "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
+            "A.3" => ProcessResult::Changed(vec![]),
+            "A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    let mut ok = ok;
     ok.sort();
     assert_eq!(ok, vec!["A.1", "A.3"]);
     assert!(err.is_empty());
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A.2.i" => ProcessResult::Unchanged,
-                "A.2.ii" => ProcessResult::Changed(vec![]),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A.2.i" => ProcessResult::Unchanged,
+            "A.2.ii" => ProcessResult::Changed(vec![]),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok, vec!["A.2.ii"]);
     assert!(err.is_empty());
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
-                "A.2.i.a" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert!(ok.unwrap().is_empty());
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
+            "A.2.i.a" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert!(ok.is_empty());
     assert!(err.is_empty());
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A.2.i.a" => ProcessResult::Changed(vec![]),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    let mut ok = ok.unwrap();
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A.2.i.a" => ProcessResult::Changed(vec![]),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    let mut ok = ok;
     ok.sort();
     assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
     assert!(err.is_empty());
 
-    let Outcome { completed: ok, errors: err, .. } =
-        forest.process_obligations(&mut C(|_| unreachable!(), |_| {}), DoCompleted::Yes);
+    let TestOutcome { completed: ok, errors: err, .. } =
+        forest.process_obligations(&mut C(|_| unreachable!(), |_| {}));
 
-    assert!(ok.unwrap().is_empty());
+    assert!(ok.is_empty());
     assert!(err.is_empty());
 }
 
@@ -235,18 +245,15 @@
     // yields to correct errors (and does not panic, in particular).
     let mut forest = ObligationForest::new();
     forest.register_obligation("A");
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
-                "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
+            "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err.len(), 0);
     let errors = forest.to_errors(());
     assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
@@ -260,51 +267,42 @@
     // check that diamond dependencies are handled correctly
     let mut forest = ObligationForest::new();
     forest.register_obligation("A");
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
-                "A.1" | "A.2" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
+            "A.1" | "A.2" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err.len(), 0);
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A.1" => ProcessResult::Changed(vec!["D"]),
-                "A.2" => ProcessResult::Changed(vec!["D"]),
-                "D" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A.1" => ProcessResult::Changed(vec!["D"]),
+            "A.2" => ProcessResult::Changed(vec!["D"]),
+            "D" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err.len(), 0);
 
     let mut d_count = 0;
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "D" => {
-                    d_count += 1;
-                    ProcessResult::Changed(vec![])
-                }
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "D" => {
+                d_count += 1;
+                ProcessResult::Changed(vec![])
+            }
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
     assert_eq!(d_count, 1);
-    let mut ok = ok.unwrap();
+    let mut ok = ok;
     ok.sort();
     assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
     assert_eq!(err.len(), 0);
@@ -313,51 +311,42 @@
     assert_eq!(errors.len(), 0);
 
     forest.register_obligation("A'");
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
-                "A'.1" | "A'.2" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
+            "A'.1" | "A'.2" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err.len(), 0);
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
-                "A'.2" => ProcessResult::Changed(vec!["D'"]),
-                "D'" | "A'" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
+            "A'.2" => ProcessResult::Changed(vec!["D'"]),
+            "D'" | "A'" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err.len(), 0);
 
     let mut d_count = 0;
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "D'" => {
-                    d_count += 1;
-                    ProcessResult::Error("operation failed")
-                }
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "D'" => {
+                d_count += 1;
+                ProcessResult::Error("operation failed")
+            }
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
     assert_eq!(d_count, 1);
-    assert_eq!(ok.unwrap().len(), 0);
+    assert_eq!(ok.len(), 0);
     assert_eq!(
         err,
         vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }]
@@ -375,35 +364,27 @@
     forest.register_obligation("B: Sized");
     forest.register_obligation("C: Sized");
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    let mut ok = ok.unwrap();
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    let mut ok = ok;
     ok.sort();
     assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
     assert_eq!(err.len(), 0);
 
     forest.register_obligation("(A,B,C): Sized");
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "(A,B,C): Sized" => {
-                    ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"])
-                }
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok, vec!["(A,B,C): Sized"]);
     assert_eq!(err.len(), 0);
 }
 
@@ -416,64 +397,52 @@
     forest.register_obligation("C1");
     forest.register_obligation("C2");
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A" => ProcessResult::Changed(vec!["D", "E"]),
-                "B" => ProcessResult::Unchanged,
-                "C1" => ProcessResult::Changed(vec![]),
-                "C2" => ProcessResult::Changed(vec![]),
-                "D" | "E" => ProcessResult::Unchanged,
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    let mut ok = ok.unwrap();
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A" => ProcessResult::Changed(vec!["D", "E"]),
+            "B" => ProcessResult::Unchanged,
+            "C1" => ProcessResult::Changed(vec![]),
+            "C2" => ProcessResult::Changed(vec![]),
+            "D" | "E" => ProcessResult::Unchanged,
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    let mut ok = ok;
     ok.sort();
     assert_eq!(ok, vec!["C1", "C2"]);
     assert_eq!(err.len(), 0);
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "D" | "E" => ProcessResult::Unchanged,
-                "B" => ProcessResult::Changed(vec!["D"]),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "D" | "E" => ProcessResult::Unchanged,
+            "B" => ProcessResult::Changed(vec!["D"]),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err.len(), 0);
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "D" => ProcessResult::Unchanged,
-                "E" => ProcessResult::Error("E is for error"),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "D" => ProcessResult::Unchanged,
+            "E" => ProcessResult::Error("E is for error"),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]);
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "D" => ProcessResult::Error("D is dead"),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "D" => ProcessResult::Error("D is dead"),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]);
 
     let errors = forest.to_errors(());
@@ -487,35 +456,29 @@
     forest.register_obligation("A");
     forest.register_obligation("B");
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A" => ProcessResult::Error("An error"),
-                "B" => ProcessResult::Changed(vec!["A"]),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A" => ProcessResult::Error("An error"),
+            "B" => ProcessResult::Changed(vec!["A"]),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
 
     let mut forest = ObligationForest::new();
     forest.register_obligation("B");
     forest.register_obligation("A");
 
-    let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
-        &mut C(
-            |obligation| match *obligation {
-                "A" => ProcessResult::Error("An error"),
-                "B" => ProcessResult::Changed(vec!["A"]),
-                _ => unreachable!(),
-            },
-            |_| {},
-        ),
-        DoCompleted::Yes,
-    );
-    assert_eq!(ok.unwrap().len(), 0);
+    let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
+        |obligation| match *obligation {
+            "A" => ProcessResult::Error("An error"),
+            "B" => ProcessResult::Changed(vec!["A"]),
+            _ => unreachable!(),
+        },
+        |_| {},
+    ));
+    assert_eq!(ok.len(), 0);
     assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
 }
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index beb28dd..2c4eff6 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -125,15 +125,28 @@
 
     // A specialized write function for values with size <= 8.
     //
-    // The hashing of multi-byte integers depends on endianness. E.g.:
+    // The input must be zero-extended to 64-bits by the caller. This extension
+    // isn't hashed, but the implementation requires it for correctness.
+    //
+    // This function, given the same integer size and value, has the same effect
+    // on both little- and big-endian hardware. It operates on values without
+    // depending on their sequence in memory, so is independent of endianness.
+    //
+    // However, we want SipHasher128 to be platform-dependent, in order to be
+    // consistent with the platform-dependent SipHasher in libstd. In other
+    // words, we want:
+    //
     // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])`
     // - big-endian:    `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])`
     //
-    // This function does the right thing for little-endian hardware. On
-    // big-endian hardware `x` must be byte-swapped first to give the right
-    // behaviour. After any byte-swapping, the input must be zero-extended to
-    // 64-bits. The caller is responsible for the byte-swapping and
-    // zero-extension.
+    // Therefore, in order to produce endian-dependent results, SipHasher128's
+    // `write_xxx` Hasher trait methods byte-swap `x` prior to zero-extending.
+    //
+    // If clients of SipHasher128 itself want platform-independent results, they
+    // *also* must byte-swap integer inputs before invoking the `write_xxx`
+    // methods on big-endian hardware (that is, two byte-swaps must occur--one
+    // in the client, and one in SipHasher128). Additionally, they must extend
+    // `usize` and `isize` types to 64 bits on 32-bit systems.
     #[inline]
     fn short_write<T>(&mut self, _x: T, x: u64) {
         let size = mem::size_of::<T>();
diff --git a/compiler/rustc_data_structures/src/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs
index 80b7fc7..2e2274a 100644
--- a/compiler/rustc_data_structures/src/sip128/tests.rs
+++ b/compiler/rustc_data_structures/src/sip128/tests.rs
@@ -1,7 +1,6 @@
 use super::*;
 
 use std::hash::{Hash, Hasher};
-use std::{mem, slice};
 
 // Hash just the bytes of the slice, without length prefix
 struct Bytes<'a>(&'a [u8]);
@@ -399,20 +398,55 @@
 }
 
 #[test]
-fn test_write_short_works() {
-    let test_usize = 0xd0c0b0a0usize;
+fn test_short_write_works() {
+    let test_u8 = 0xFF_u8;
+    let test_u16 = 0x1122_u16;
+    let test_u32 = 0x22334455_u32;
+    let test_u64 = 0x33445566_778899AA_u64;
+    let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128;
+    let test_usize = 0xD0C0B0A0_usize;
+
+    let test_i8 = -1_i8;
+    let test_i16 = -2_i16;
+    let test_i32 = -3_i32;
+    let test_i64 = -4_i64;
+    let test_i128 = -5_i128;
+    let test_isize = -6_isize;
+
     let mut h1 = SipHasher128::new_with_keys(0, 0);
-    h1.write_usize(test_usize);
     h1.write(b"bytes");
     h1.write(b"string");
-    h1.write_u8(0xFFu8);
-    h1.write_u8(0x01u8);
+    h1.write_u8(test_u8);
+    h1.write_u16(test_u16);
+    h1.write_u32(test_u32);
+    h1.write_u64(test_u64);
+    h1.write_u128(test_u128);
+    h1.write_usize(test_usize);
+    h1.write_i8(test_i8);
+    h1.write_i16(test_i16);
+    h1.write_i32(test_i32);
+    h1.write_i64(test_i64);
+    h1.write_i128(test_i128);
+    h1.write_isize(test_isize);
+
     let mut h2 = SipHasher128::new_with_keys(0, 0);
-    h2.write(unsafe {
-        slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::<usize>())
-    });
     h2.write(b"bytes");
     h2.write(b"string");
-    h2.write(&[0xFFu8, 0x01u8]);
-    assert_eq!(h1.finish128(), h2.finish128());
+    h2.write(&test_u8.to_ne_bytes());
+    h2.write(&test_u16.to_ne_bytes());
+    h2.write(&test_u32.to_ne_bytes());
+    h2.write(&test_u64.to_ne_bytes());
+    h2.write(&test_u128.to_ne_bytes());
+    h2.write(&test_usize.to_ne_bytes());
+    h2.write(&test_i8.to_ne_bytes());
+    h2.write(&test_i16.to_ne_bytes());
+    h2.write(&test_i32.to_ne_bytes());
+    h2.write(&test_i64.to_ne_bytes());
+    h2.write(&test_i128.to_ne_bytes());
+    h2.write(&test_isize.to_ne_bytes());
+
+    let h1_hash = h1.finish128();
+    let h2_hash = h2.finish128();
+
+    assert_eq!(h1_hash, h2_hash);
 }
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 4807380..9a28f8f 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -93,7 +93,7 @@
 
     /// Iterate over elements, sorted by key
     #[inline]
-    pub fn iter(&self) -> ::std::slice::Iter<'_, (K, V)> {
+    pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> {
         self.data.iter()
     }
 
@@ -134,7 +134,7 @@
         R: RangeBounds<K>,
     {
         let (start, end) = self.range_slice_indices(range);
-        self.data.splice(start..end, ::std::iter::empty());
+        self.data.splice(start..end, std::iter::empty());
     }
 
     /// Mutate all keys with the given function `f`. This mutation must not
@@ -241,7 +241,7 @@
 
 impl<K: Ord, V> IntoIterator for SortedMap<K, V> {
     type Item = (K, V);
-    type IntoIter = ::std::vec::IntoIter<(K, V)>;
+    type IntoIter = std::vec::IntoIter<(K, V)>;
 
     fn into_iter(self) -> Self::IntoIter {
         self.data.into_iter()
diff --git a/compiler/rustc_data_structures/src/sso/either_iter.rs b/compiler/rustc_data_structures/src/sso/either_iter.rs
new file mode 100644
index 0000000..af8ffcf
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sso/either_iter.rs
@@ -0,0 +1,75 @@
+use std::fmt;
+use std::iter::ExactSizeIterator;
+use std::iter::FusedIterator;
+use std::iter::Iterator;
+
+/// Iterator which may contain instance of
+/// one of two specific implementations.
+///
+/// Note: For most methods providing custom
+///       implementation may margianlly
+///       improve performance by avoiding
+///       doing Left/Right match on every step
+///       and doing it only once instead.
+#[derive(Clone)]
+pub enum EitherIter<L, R> {
+    Left(L),
+    Right(R),
+}
+
+impl<L, R> Iterator for EitherIter<L, R>
+where
+    L: Iterator,
+    R: Iterator<Item = L::Item>,
+{
+    type Item = L::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            EitherIter::Left(l) => l.next(),
+            EitherIter::Right(r) => r.next(),
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        match self {
+            EitherIter::Left(l) => l.size_hint(),
+            EitherIter::Right(r) => r.size_hint(),
+        }
+    }
+}
+
+impl<L, R> ExactSizeIterator for EitherIter<L, R>
+where
+    L: ExactSizeIterator,
+    R: ExactSizeIterator,
+    EitherIter<L, R>: Iterator,
+{
+    fn len(&self) -> usize {
+        match self {
+            EitherIter::Left(l) => l.len(),
+            EitherIter::Right(r) => r.len(),
+        }
+    }
+}
+
+impl<L, R> FusedIterator for EitherIter<L, R>
+where
+    L: FusedIterator,
+    R: FusedIterator,
+    EitherIter<L, R>: Iterator,
+{
+}
+
+impl<L, R> fmt::Debug for EitherIter<L, R>
+where
+    L: fmt::Debug,
+    R: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            EitherIter::Left(l) => l.fmt(f),
+            EitherIter::Right(r) => r.fmt(f),
+        }
+    }
+}
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
new file mode 100644
index 0000000..fa510e5
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -0,0 +1,560 @@
+use super::either_iter::EitherIter;
+use crate::fx::FxHashMap;
+use arrayvec::ArrayVec;
+use std::fmt;
+use std::hash::Hash;
+use std::iter::FromIterator;
+use std::ops::Index;
+
+// For pointer-sized arguments arrays
+// are faster than set/map for up to 64
+// arguments.
+//
+// On the other hand such a big array
+// hurts cache performance, makes passing
+// sso structures around very expensive.
+//
+// Biggest performance benefit is gained
+// for reasonably small arrays that stay
+// small in vast majority of cases.
+//
+// '8' is choosen as a sane default, to be
+// reevaluated later.
+//
+// Note: As of now ArrayVec design prevents
+//       us from making it user-customizable.
+const SSO_ARRAY_SIZE: usize = 8;
+
+/// Small-storage-optimized implementation of a map.
+///
+/// Stores elements in a small array up to a certain length
+/// and switches to `HashMap` when that length is exceeded.
+//
+// FIXME: Implements subset of HashMap API.
+//
+// Missing HashMap API:
+//   all hasher-related
+//   try_reserve (unstable)
+//   shrink_to (unstable)
+//   drain_filter (unstable)
+//   into_keys/into_values (unstable)
+//   all raw_entry-related
+//   PartialEq/Eq (requires sorting the array)
+//   Entry::or_insert_with_key (unstable)
+//   Vacant/Occupied entries and related
+//
+// FIXME: In HashMap most methods accepting key reference
+// accept reference to generic `Q` where `K: Borrow<Q>`.
+//
+// However, using this approach in `HashMap::get` apparently
+// breaks inlining and noticeably reduces performance.
+//
+// Performance *should* be the same given that borrow is
+// a NOP in most cases, but in practice that's not the case.
+//
+// Further investigation is required.
+//
+// Affected methods:
+//   SsoHashMap::get
+//   SsoHashMap::get_mut
+//   SsoHashMap::get_entry
+//   SsoHashMap::get_key_value
+//   SsoHashMap::contains_key
+//   SsoHashMap::remove
+//   SsoHashMap::remove_entry
+//   Index::index
+//   SsoHashSet::take
+//   SsoHashSet::get
+//   SsoHashSet::remove
+//   SsoHashSet::contains
+
+#[derive(Clone)]
+pub enum SsoHashMap<K, V> {
+    Array(ArrayVec<[(K, V); SSO_ARRAY_SIZE]>),
+    Map(FxHashMap<K, V>),
+}
+
+impl<K, V> SsoHashMap<K, V> {
+    /// Creates an empty `SsoHashMap`.
+    #[inline]
+    pub fn new() -> Self {
+        SsoHashMap::Array(ArrayVec::new())
+    }
+
+    /// Creates an empty `SsoHashMap` with the specified capacity.
+    pub fn with_capacity(cap: usize) -> Self {
+        if cap <= SSO_ARRAY_SIZE {
+            Self::new()
+        } else {
+            SsoHashMap::Map(FxHashMap::with_capacity_and_hasher(cap, Default::default()))
+        }
+    }
+
+    /// Clears the map, removing all key-value pairs. Keeps the allocated memory
+    /// for reuse.
+    pub fn clear(&mut self) {
+        match self {
+            SsoHashMap::Array(array) => array.clear(),
+            SsoHashMap::Map(map) => map.clear(),
+        }
+    }
+
+    /// Returns the number of elements the map can hold without reallocating.
+    pub fn capacity(&self) -> usize {
+        match self {
+            SsoHashMap::Array(_) => SSO_ARRAY_SIZE,
+            SsoHashMap::Map(map) => map.capacity(),
+        }
+    }
+
+    /// Returns the number of elements in the map.
+    pub fn len(&self) -> usize {
+        match self {
+            SsoHashMap::Array(array) => array.len(),
+            SsoHashMap::Map(map) => map.len(),
+        }
+    }
+
+    /// Returns `true` if the map contains no elements.
+    pub fn is_empty(&self) -> bool {
+        match self {
+            SsoHashMap::Array(array) => array.is_empty(),
+            SsoHashMap::Map(map) => map.is_empty(),
+        }
+    }
+
+    /// An iterator visiting all key-value pairs in arbitrary order.
+    /// The iterator element type is `(&'a K, &'a V)`.
+    #[inline]
+    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
+        self.into_iter()
+    }
+
+    /// An iterator visiting all key-value pairs in arbitrary order,
+    /// with mutable references to the values.
+    /// The iterator element type is `(&'a K, &'a mut V)`.
+    #[inline]
+    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&'_ K, &'_ mut V)> {
+        self.into_iter()
+    }
+
+    /// An iterator visiting all keys in arbitrary order.
+    /// The iterator element type is `&'a K`.
+    pub fn keys(&self) -> impl Iterator<Item = &'_ K> {
+        match self {
+            SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(k, _v)| k)),
+            SsoHashMap::Map(map) => EitherIter::Right(map.keys()),
+        }
+    }
+
+    /// An iterator visiting all values in arbitrary order.
+    /// The iterator element type is `&'a V`.
+    pub fn values(&self) -> impl Iterator<Item = &'_ V> {
+        match self {
+            SsoHashMap::Array(array) => EitherIter::Left(array.iter().map(|(_k, v)| v)),
+            SsoHashMap::Map(map) => EitherIter::Right(map.values()),
+        }
+    }
+
+    /// An iterator visiting all values mutably in arbitrary order.
+    /// The iterator element type is `&'a mut V`.
+    pub fn values_mut(&mut self) -> impl Iterator<Item = &'_ mut V> {
+        match self {
+            SsoHashMap::Array(array) => EitherIter::Left(array.iter_mut().map(|(_k, v)| v)),
+            SsoHashMap::Map(map) => EitherIter::Right(map.values_mut()),
+        }
+    }
+
+    /// Clears the map, returning all key-value pairs as an iterator. Keeps the
+    /// allocated memory for reuse.
+    pub fn drain(&mut self) -> impl Iterator<Item = (K, V)> + '_ {
+        match self {
+            SsoHashMap::Array(array) => EitherIter::Left(array.drain(..)),
+            SsoHashMap::Map(map) => EitherIter::Right(map.drain()),
+        }
+    }
+}
+
+impl<K: Eq + Hash, V> SsoHashMap<K, V> {
+    /// Changes underlying storage from array to hashmap
+    /// if array is full.
+    fn migrate_if_full(&mut self) {
+        if let SsoHashMap::Array(array) = self {
+            if array.is_full() {
+                *self = SsoHashMap::Map(array.drain(..).collect());
+            }
+        }
+    }
+
+    /// Reserves capacity for at least `additional` more elements to be inserted
+    /// in the `SsoHashMap`. The collection may reserve more space to avoid
+    /// frequent reallocations.
+    pub fn reserve(&mut self, additional: usize) {
+        match self {
+            SsoHashMap::Array(array) => {
+                if SSO_ARRAY_SIZE < (array.len() + additional) {
+                    let mut map: FxHashMap<K, V> = array.drain(..).collect();
+                    map.reserve(additional);
+                    *self = SsoHashMap::Map(map);
+                }
+            }
+            SsoHashMap::Map(map) => map.reserve(additional),
+        }
+    }
+
+    /// Shrinks the capacity of the map as much as possible. It will drop
+    /// down as much as possible while maintaining the internal rules
+    /// and possibly leaving some space in accordance with the resize policy.
+    pub fn shrink_to_fit(&mut self) {
+        if let SsoHashMap::Map(map) = self {
+            if map.len() <= SSO_ARRAY_SIZE {
+                *self = SsoHashMap::Array(map.drain().collect());
+            } else {
+                map.shrink_to_fit();
+            }
+        }
+    }
+
+    /// Retains only the elements specified by the predicate.
+    pub fn retain<F>(&mut self, mut f: F)
+    where
+        F: FnMut(&K, &mut V) -> bool,
+    {
+        match self {
+            SsoHashMap::Array(array) => array.retain(|(k, v)| f(k, v)),
+            SsoHashMap::Map(map) => map.retain(f),
+        }
+    }
+
+    /// Inserts a key-value pair into the map.
+    ///
+    /// If the map did not have this key present, [`None`] is returned.
+    ///
+    /// If the map did have this key present, the value is updated, and the old
+    /// value is returned. The key is not updated, though; this matters for
+    /// types that can be `==` without being identical. See the [module-level
+    /// documentation] for more.
+    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
+        match self {
+            SsoHashMap::Array(array) => {
+                for (k, v) in array.iter_mut() {
+                    if *k == key {
+                        let old_value = std::mem::replace(v, value);
+                        return Some(old_value);
+                    }
+                }
+                if let Err(error) = array.try_push((key, value)) {
+                    let mut map: FxHashMap<K, V> = array.drain(..).collect();
+                    let (key, value) = error.element();
+                    map.insert(key, value);
+                    *self = SsoHashMap::Map(map);
+                }
+                None
+            }
+            SsoHashMap::Map(map) => map.insert(key, value),
+        }
+    }
+
+    /// Removes a key from the map, returning the value at the key if the key
+    /// was previously in the map.
+    pub fn remove(&mut self, key: &K) -> Option<V> {
+        match self {
+            SsoHashMap::Array(array) => {
+                if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+                    Some(array.swap_remove(index).1)
+                } else {
+                    None
+                }
+            }
+            SsoHashMap::Map(map) => map.remove(key),
+        }
+    }
+
+    /// Removes a key from the map, returning the stored key and value if the
+    /// key was previously in the map.
+    pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> {
+        match self {
+            SsoHashMap::Array(array) => {
+                if let Some(index) = array.iter().position(|(k, _v)| k == key) {
+                    Some(array.swap_remove(index))
+                } else {
+                    None
+                }
+            }
+            SsoHashMap::Map(map) => map.remove_entry(key),
+        }
+    }
+
+    /// Returns a reference to the value corresponding to the key.
+    pub fn get(&self, key: &K) -> Option<&V> {
+        match self {
+            SsoHashMap::Array(array) => {
+                for (k, v) in array {
+                    if k == key {
+                        return Some(v);
+                    }
+                }
+                None
+            }
+            SsoHashMap::Map(map) => map.get(key),
+        }
+    }
+
+    /// Returns a mutable reference to the value corresponding to the key.
+    pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
+        match self {
+            SsoHashMap::Array(array) => {
+                for (k, v) in array {
+                    if k == key {
+                        return Some(v);
+                    }
+                }
+                None
+            }
+            SsoHashMap::Map(map) => map.get_mut(key),
+        }
+    }
+
+    /// Returns the key-value pair corresponding to the supplied key.
+    pub fn get_key_value(&self, key: &K) -> Option<(&K, &V)> {
+        match self {
+            SsoHashMap::Array(array) => {
+                for (k, v) in array {
+                    if k == key {
+                        return Some((k, v));
+                    }
+                }
+                None
+            }
+            SsoHashMap::Map(map) => map.get_key_value(key),
+        }
+    }
+
+    /// Returns `true` if the map contains a value for the specified key.
+    pub fn contains_key(&self, key: &K) -> bool {
+        match self {
+            SsoHashMap::Array(array) => array.iter().any(|(k, _v)| k == key),
+            SsoHashMap::Map(map) => map.contains_key(key),
+        }
+    }
+
+    /// Gets the given key's corresponding entry in the map for in-place manipulation.
+    #[inline]
+    pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
+        Entry { ssomap: self, key }
+    }
+}
+
+impl<K, V> Default for SsoHashMap<K, V> {
+    #[inline]
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<K: Eq + Hash, V> FromIterator<(K, V)> for SsoHashMap<K, V> {
+    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> SsoHashMap<K, V> {
+        let mut map: SsoHashMap<K, V> = Default::default();
+        map.extend(iter);
+        map
+    }
+}
+
+impl<K: Eq + Hash, V> Extend<(K, V)> for SsoHashMap<K, V> {
+    fn extend<I>(&mut self, iter: I)
+    where
+        I: IntoIterator<Item = (K, V)>,
+    {
+        for (key, value) in iter.into_iter() {
+            self.insert(key, value);
+        }
+    }
+
+    #[inline]
+    fn extend_one(&mut self, (k, v): (K, V)) {
+        self.insert(k, v);
+    }
+
+    fn extend_reserve(&mut self, additional: usize) {
+        match self {
+            SsoHashMap::Array(array) => {
+                if SSO_ARRAY_SIZE < (array.len() + additional) {
+                    let mut map: FxHashMap<K, V> = array.drain(..).collect();
+                    map.extend_reserve(additional);
+                    *self = SsoHashMap::Map(map);
+                }
+            }
+            SsoHashMap::Map(map) => map.extend_reserve(additional),
+        }
+    }
+}
+
+impl<'a, K, V> Extend<(&'a K, &'a V)> for SsoHashMap<K, V>
+where
+    K: Eq + Hash + Copy,
+    V: Copy,
+{
+    fn extend<T: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: T) {
+        self.extend(iter.into_iter().map(|(k, v)| (k.clone(), v.clone())))
+    }
+
+    #[inline]
+    fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) {
+        self.insert(k, v);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        Extend::<(K, V)>::extend_reserve(self, additional)
+    }
+}
+
+impl<K, V> IntoIterator for SsoHashMap<K, V> {
+    type IntoIter = EitherIter<
+        <ArrayVec<[(K, V); 8]> as IntoIterator>::IntoIter,
+        <FxHashMap<K, V> as IntoIterator>::IntoIter,
+    >;
+    type Item = <Self::IntoIter as Iterator>::Item;
+
+    fn into_iter(self) -> Self::IntoIter {
+        match self {
+            SsoHashMap::Array(array) => EitherIter::Left(array.into_iter()),
+            SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()),
+        }
+    }
+}
+
+/// adapts Item of array reference iterator to Item of hashmap reference iterator.
+#[inline(always)]
+fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) {
+    let (a, b) = pair;
+    (a, b)
+}
+
+/// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator.
+#[inline(always)]
+fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) {
+    let (a, b) = pair;
+    (a, b)
+}
+
+impl<'a, K, V> IntoIterator for &'a SsoHashMap<K, V> {
+    type IntoIter = EitherIter<
+        std::iter::Map<
+            <&'a ArrayVec<[(K, V); 8]> as IntoIterator>::IntoIter,
+            fn(&'a (K, V)) -> (&'a K, &'a V),
+        >,
+        <&'a FxHashMap<K, V> as IntoIterator>::IntoIter,
+    >;
+    type Item = <Self::IntoIter as Iterator>::Item;
+
+    fn into_iter(self) -> Self::IntoIter {
+        match self {
+            SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_ref_it)),
+            SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()),
+        }
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut SsoHashMap<K, V> {
+    type IntoIter = EitherIter<
+        std::iter::Map<
+            <&'a mut ArrayVec<[(K, V); 8]> as IntoIterator>::IntoIter,
+            fn(&'a mut (K, V)) -> (&'a K, &'a mut V),
+        >,
+        <&'a mut FxHashMap<K, V> as IntoIterator>::IntoIter,
+    >;
+    type Item = <Self::IntoIter as Iterator>::Item;
+
+    fn into_iter(self) -> Self::IntoIter {
+        match self {
+            SsoHashMap::Array(array) => EitherIter::Left(array.into_iter().map(adapt_array_mut_it)),
+            SsoHashMap::Map(map) => EitherIter::Right(map.into_iter()),
+        }
+    }
+}
+
+impl<K, V> fmt::Debug for SsoHashMap<K, V>
+where
+    K: fmt::Debug,
+    V: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_map().entries(self.iter()).finish()
+    }
+}
+
+impl<'a, K, V> Index<&'a K> for SsoHashMap<K, V>
+where
+    K: Eq + Hash,
+{
+    type Output = V;
+
+    #[inline]
+    fn index(&self, key: &K) -> &V {
+        self.get(key).expect("no entry found for key")
+    }
+}
+
+/// A view into a single entry in a map.
+pub struct Entry<'a, K, V> {
+    ssomap: &'a mut SsoHashMap<K, V>,
+    key: K,
+}
+
+impl<'a, K: Eq + Hash, V> Entry<'a, K, V> {
+    /// Provides in-place mutable access to an occupied entry before any
+    /// potential inserts into the map.
+    pub fn and_modify<F>(self, f: F) -> Self
+    where
+        F: FnOnce(&mut V),
+    {
+        if let Some(value) = self.ssomap.get_mut(&self.key) {
+            f(value);
+        }
+        self
+    }
+
+    /// Ensures a value is in the entry by inserting the default if empty, and returns
+    /// a mutable reference to the value in the entry.
+    #[inline]
+    pub fn or_insert(self, value: V) -> &'a mut V {
+        self.or_insert_with(|| value)
+    }
+
+    /// Ensures a value is in the entry by inserting the result of the default function if empty,
+    /// and returns a mutable reference to the value in the entry.
+    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+        self.ssomap.migrate_if_full();
+        match self.ssomap {
+            SsoHashMap::Array(array) => {
+                let key_ref = &self.key;
+                let found_index = array.iter().position(|(k, _v)| k == key_ref);
+                let index = if let Some(index) = found_index {
+                    index
+                } else {
+                    let index = array.len();
+                    array.try_push((self.key, default())).unwrap();
+                    index
+                };
+                &mut array[index].1
+            }
+            SsoHashMap::Map(map) => map.entry(self.key).or_insert_with(default),
+        }
+    }
+
+    /// Returns a reference to this entry's key.
+    #[inline]
+    pub fn key(&self) -> &K {
+        &self.key
+    }
+}
+
+impl<'a, K: Eq + Hash, V: Default> Entry<'a, K, V> {
+    /// Ensures a value is in the entry by inserting the default value if empty,
+    /// and returns a mutable reference to the value in the entry.
+    #[inline]
+    pub fn or_default(self) -> &'a mut V {
+        self.or_insert_with(Default::default)
+    }
+}
diff --git a/compiler/rustc_data_structures/src/sso/mod.rs b/compiler/rustc_data_structures/src/sso/mod.rs
new file mode 100644
index 0000000..dd21bc8
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sso/mod.rs
@@ -0,0 +1,6 @@
+mod either_iter;
+mod map;
+mod set;
+
+pub use map::SsoHashMap;
+pub use set::SsoHashSet;
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
new file mode 100644
index 0000000..23cff02
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -0,0 +1,237 @@
+use std::fmt;
+use std::hash::Hash;
+use std::iter::FromIterator;
+
+use super::map::SsoHashMap;
+
+/// Small-storage-optimized implementation of a set.
+///
+/// Stores elements in a small array up to a certain length
+/// and switches to `HashSet` when that length is exceeded.
+//
+// FIXME: Implements subset of HashSet API.
+//
+// Missing HashSet API:
+//   all hasher-related
+//   try_reserve (unstable)
+//   shrink_to (unstable)
+//   drain_filter (unstable)
+//   replace
+//   get_or_insert/get_or_insert_owned/get_or_insert_with (unstable)
+//   difference/symmetric_difference/intersection/union
+//   is_disjoint/is_subset/is_superset
+//   PartialEq/Eq (requires SsoHashMap implementation)
+//   BitOr/BitAnd/BitXor/Sub
+#[derive(Clone)]
+pub struct SsoHashSet<T> {
+    map: SsoHashMap<T, ()>,
+}
+
+/// Adapter function used ot return
+/// result if SsoHashMap functions into
+/// result SsoHashSet should return.
+#[inline(always)]
+fn entry_to_key<K, V>((k, _v): (K, V)) -> K {
+    k
+}
+
+impl<T> SsoHashSet<T> {
+    /// Creates an empty `SsoHashSet`.
+    #[inline]
+    pub fn new() -> Self {
+        Self { map: SsoHashMap::new() }
+    }
+
+    /// Creates an empty `SsoHashSet` with the specified capacity.
+    #[inline]
+    pub fn with_capacity(cap: usize) -> Self {
+        Self { map: SsoHashMap::with_capacity(cap) }
+    }
+
+    /// Clears the set, removing all values.
+    #[inline]
+    pub fn clear(&mut self) {
+        self.map.clear()
+    }
+
+    /// Returns the number of elements the set can hold without reallocating.
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.map.capacity()
+    }
+
+    /// Returns the number of elements in the set.
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.map.len()
+    }
+
+    /// Returns `true` if the set contains no elements.
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.map.is_empty()
+    }
+
+    /// An iterator visiting all elements in arbitrary order.
+    /// The iterator element type is `&'a T`.
+    #[inline]
+    pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
+        self.into_iter()
+    }
+
+    /// Clears the set, returning all elements in an iterator.
+    #[inline]
+    pub fn drain(&mut self) -> impl Iterator<Item = T> + '_ {
+        self.map.drain().map(entry_to_key)
+    }
+}
+
+impl<T: Eq + Hash> SsoHashSet<T> {
+    /// Reserves capacity for at least `additional` more elements to be inserted
+    /// in the `SsoHashSet`. The collection may reserve more space to avoid
+    /// frequent reallocations.
+    #[inline]
+    pub fn reserve(&mut self, additional: usize) {
+        self.map.reserve(additional)
+    }
+
+    /// Shrinks the capacity of the set as much as possible. It will drop
+    /// down as much as possible while maintaining the internal rules
+    /// and possibly leaving some space in accordance with the resize policy.
+    #[inline]
+    pub fn shrink_to_fit(&mut self) {
+        self.map.shrink_to_fit()
+    }
+
+    /// Retains only the elements specified by the predicate.
+    #[inline]
+    pub fn retain<F>(&mut self, mut f: F)
+    where
+        F: FnMut(&T) -> bool,
+    {
+        self.map.retain(|k, _v| f(k))
+    }
+
+    /// Removes and returns the value in the set, if any, that is equal to the given one.
+    #[inline]
+    pub fn take(&mut self, value: &T) -> Option<T> {
+        self.map.remove_entry(value).map(entry_to_key)
+    }
+
+    /// Returns a reference to the value in the set, if any, that is equal to the given value.
+    #[inline]
+    pub fn get(&self, value: &T) -> Option<&T> {
+        self.map.get_key_value(value).map(entry_to_key)
+    }
+
+    /// Adds a value to the set.
+    ///
+    /// If the set did not have this value present, `true` is returned.
+    ///
+    /// If the set did have this value present, `false` is returned.
+    #[inline]
+    pub fn insert(&mut self, elem: T) -> bool {
+        self.map.insert(elem, ()).is_none()
+    }
+
+    /// Removes a value from the set. Returns whether the value was
+    /// present in the set.
+    #[inline]
+    pub fn remove(&mut self, value: &T) -> bool {
+        self.map.remove(value).is_some()
+    }
+
+    /// Returns `true` if the set contains a value.
+    #[inline]
+    pub fn contains(&self, value: &T) -> bool {
+        self.map.contains_key(value)
+    }
+}
+
+impl<T: Eq + Hash> FromIterator<T> for SsoHashSet<T> {
+    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> SsoHashSet<T> {
+        let mut set: SsoHashSet<T> = Default::default();
+        set.extend(iter);
+        set
+    }
+}
+
+impl<T> Default for SsoHashSet<T> {
+    #[inline]
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T: Eq + Hash> Extend<T> for SsoHashSet<T> {
+    fn extend<I>(&mut self, iter: I)
+    where
+        I: IntoIterator<Item = T>,
+    {
+        for val in iter.into_iter() {
+            self.insert(val);
+        }
+    }
+
+    #[inline]
+    fn extend_one(&mut self, item: T) {
+        self.insert(item);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        self.map.extend_reserve(additional)
+    }
+}
+
+impl<'a, T> Extend<&'a T> for SsoHashSet<T>
+where
+    T: 'a + Eq + Hash + Copy,
+{
+    #[inline]
+    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+        self.extend(iter.into_iter().cloned());
+    }
+
+    #[inline]
+    fn extend_one(&mut self, &item: &'a T) {
+        self.insert(item);
+    }
+
+    #[inline]
+    fn extend_reserve(&mut self, additional: usize) {
+        Extend::<T>::extend_reserve(self, additional)
+    }
+}
+
+impl<T> IntoIterator for SsoHashSet<T> {
+    type IntoIter = std::iter::Map<<SsoHashMap<T, ()> as IntoIterator>::IntoIter, fn((T, ())) -> T>;
+    type Item = <Self::IntoIter as Iterator>::Item;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.map.into_iter().map(entry_to_key)
+    }
+}
+
+impl<'a, T> IntoIterator for &'a SsoHashSet<T> {
+    type IntoIter = std::iter::Map<
+        <&'a SsoHashMap<T, ()> as IntoIterator>::IntoIter,
+        fn((&'a T, &'a ())) -> &'a T,
+    >;
+    type Item = <Self::IntoIter as Iterator>::Item;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.map.iter().map(entry_to_key)
+    }
+}
+
+impl<T> fmt::Debug for SsoHashSet<T>
+where
+    T: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_set().entries(self.iter()).finish()
+    }
+}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index c1c79b1..579eb1c 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -5,6 +5,9 @@
 use std::hash::{BuildHasher, Hash, Hasher};
 use std::mem;
 
+#[cfg(test)]
+mod tests;
+
 /// When hashing something that ends up affecting properties like symbol names,
 /// we want these symbol names to be calculated independently of other factors
 /// like what architecture you're compiling *from*.
@@ -17,7 +20,7 @@
 }
 
 impl ::std::fmt::Debug for StableHasher {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{:?}", self.state)
     }
 }
@@ -129,7 +132,8 @@
     fn write_isize(&mut self, i: isize) {
         // Always treat isize as i64 so we get the same results on 32 and 64 bit
         // platforms. This is important for symbol hashes when cross compiling,
-        // for example.
+        // for example. Sign extending here is preferable as it means that the
+        // same negative number hashes the same on both 32 and 64 bit platforms.
         self.state.write_i64((i as i64).to_le());
     }
 }
diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
new file mode 100644
index 0000000..cd6ff96
--- /dev/null
+++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
@@ -0,0 +1,73 @@
+use super::*;
+
+// The tests below compare the computed hashes to particular expected values
+// in order to test that we produce the same results on different platforms,
+// regardless of endianness and `usize` and `isize` size differences (this
+// of course assumes we run these tests on platforms that differ in those
+// ways). The expected values depend on the hashing algorithm used, so they
+// need to be updated whenever StableHasher changes its hashing algorithm.
+
+#[test]
+fn test_hash_integers() {
+    // Test that integers are handled consistently across platforms.
+    let test_u8 = 0xAB_u8;
+    let test_u16 = 0xFFEE_u16;
+    let test_u32 = 0x445577AA_u32;
+    let test_u64 = 0x01234567_13243546_u64;
+    let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128;
+    let test_usize = 0xD0C0B0A0_usize;
+
+    let test_i8 = -100_i8;
+    let test_i16 = -200_i16;
+    let test_i32 = -300_i32;
+    let test_i64 = -400_i64;
+    let test_i128 = -500_i128;
+    let test_isize = -600_isize;
+
+    let mut h = StableHasher::new();
+    test_u8.hash(&mut h);
+    test_u16.hash(&mut h);
+    test_u32.hash(&mut h);
+    test_u64.hash(&mut h);
+    test_u128.hash(&mut h);
+    test_usize.hash(&mut h);
+    test_i8.hash(&mut h);
+    test_i16.hash(&mut h);
+    test_i32.hash(&mut h);
+    test_i64.hash(&mut h);
+    test_i128.hash(&mut h);
+    test_isize.hash(&mut h);
+
+    // This depends on the hashing algorithm. See note at top of file.
+    let expected = (2736651863462566372, 8121090595289675650);
+
+    assert_eq!(h.finalize(), expected);
+}
+
+#[test]
+fn test_hash_usize() {
+    // Test that usize specifically is handled consistently across platforms.
+    let test_usize = 0xABCDEF01_usize;
+
+    let mut h = StableHasher::new();
+    test_usize.hash(&mut h);
+
+    // This depends on the hashing algorithm. See note at top of file.
+    let expected = (5798740672699530587, 11186240177685111648);
+
+    assert_eq!(h.finalize(), expected);
+}
+
+#[test]
+fn test_hash_isize() {
+    // Test that isize specifically is handled consistently across platforms.
+    let test_isize = -7_isize;
+
+    let mut h = StableHasher::new();
+    test_isize.hash(&mut h);
+
+    // This depends on the hashing algorithm. See note at top of file.
+    let expected = (14721296605626097289, 11385941877786388409);
+
+    assert_eq!(h.finalize(), expected);
+}
diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs
index 0c848eb..cc562bc 100644
--- a/compiler/rustc_data_structures/src/work_queue.rs
+++ b/compiler/rustc_data_structures/src/work_queue.rs
@@ -14,12 +14,6 @@
 }
 
 impl<T: Idx> WorkQueue<T> {
-    /// Creates a new work queue with all the elements from (0..len).
-    #[inline]
-    pub fn with_all(len: usize) -> Self {
-        WorkQueue { deque: (0..len).map(T::new).collect(), set: BitSet::new_filled(len) }
-    }
-
     /// Creates a new work queue that starts empty, where elements range from (0..len).
     #[inline]
     pub fn with_none(len: usize) -> Self {
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index adfce10..0adc006 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -10,7 +10,8 @@
 [dependencies]
 libc = "0.2"
 tracing = { version = "0.1.18" }
-tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-subscriber = { version = "0.2.13", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-tree = "0.1.6"
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 7118437..d99e335 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -134,13 +134,59 @@
     Registry::new(&rustc_error_codes::DIAGNOSTICS)
 }
 
+pub struct RunCompiler<'a, 'b> {
+    at_args: &'a [String],
+    callbacks: &'b mut (dyn Callbacks + Send),
+    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    emitter: Option<Box<dyn Write + Send>>,
+    make_codegen_backend:
+        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
+}
+
+impl<'a, 'b> RunCompiler<'a, 'b> {
+    pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
+        Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
+    }
+    pub fn set_make_codegen_backend(
+        &mut self,
+        make_codegen_backend: Option<
+            Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+        >,
+    ) -> &mut Self {
+        self.make_codegen_backend = make_codegen_backend;
+        self
+    }
+    pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self {
+        self.emitter = emitter;
+        self
+    }
+    pub fn set_file_loader(
+        &mut self,
+        file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    ) -> &mut Self {
+        self.file_loader = file_loader;
+        self
+    }
+    pub fn run(self) -> interface::Result<()> {
+        run_compiler(
+            self.at_args,
+            self.callbacks,
+            self.file_loader,
+            self.emitter,
+            self.make_codegen_backend,
+        )
+    }
+}
 // Parse args and run the compiler. This is the primary entry point for rustc.
 // The FileLoader provides a way to load files from sources other than the file system.
-pub fn run_compiler(
+fn run_compiler(
     at_args: &[String],
     callbacks: &mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     emitter: Option<Box<dyn Write + Send>>,
+    make_codegen_backend: Option<
+        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+    >,
 ) -> interface::Result<()> {
     let mut args = Vec::new();
     for arg in at_args {
@@ -152,8 +198,7 @@
             ),
         }
     }
-    let diagnostic_output =
-        emitter.map(|emitter| DiagnosticOutput::Raw(emitter)).unwrap_or(DiagnosticOutput::Default);
+    let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
     let matches = match handle_options(&args) {
         Some(matches) => matches,
         None => return Ok(()),
@@ -162,6 +207,11 @@
     let sopts = config::build_session_options(&matches);
     let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
 
+    // We wrap `make_codegen_backend` in another `Option` such that `dummy_config` can take
+    // ownership of it when necessary, while also allowing the non-dummy config to take ownership
+    // when `dummy_config` is not used.
+    let mut make_codegen_backend = Some(make_codegen_backend);
+
     let mut dummy_config = |sopts, cfg, diagnostic_output| {
         let mut config = interface::Config {
             opts: sopts,
@@ -177,6 +227,7 @@
             lint_caps: Default::default(),
             register_lints: None,
             override_queries: None,
+            make_codegen_backend: make_codegen_backend.take().unwrap(),
             registry: diagnostics_registry(),
         };
         callbacks.config(&mut config);
@@ -253,6 +304,7 @@
         lint_caps: Default::default(),
         register_lints: None,
         override_queries: None,
+        make_codegen_backend: make_codegen_backend.unwrap(),
         registry: diagnostics_registry(),
     };
 
@@ -590,7 +642,7 @@
             let codegen_results: CodegenResults = json::decode(&rlink_data).unwrap_or_else(|err| {
                 sess.fatal(&format!("failed to decode rlink: {}", err));
             });
-            compiler.codegen_backend().link(&sess, Box::new(codegen_results), &outputs)
+            compiler.codegen_backend().link(&sess, codegen_results, &outputs)
         } else {
             sess.fatal("rlink must be a file")
         }
@@ -618,7 +670,7 @@
                 Input::File(ref ifile) => {
                     let path = &(*ifile);
                     let mut v = Vec::new();
-                    locator::list_file_metadata(&sess.target.target, path, metadata_loader, &mut v)
+                    locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
                         .unwrap();
                     println!("{}", String::from_utf8(v).unwrap());
                 }
@@ -662,7 +714,8 @@
         for req in &sess.opts.prints {
             match *req {
                 TargetList => {
-                    let mut targets = rustc_target::spec::get_targets().collect::<Vec<String>>();
+                    let mut targets =
+                        rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
                     targets.sort();
                     println!("{}", targets.join("\n"));
                 }
@@ -671,7 +724,7 @@
                     "{}",
                     sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display()
                 ),
-                TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
+                TargetSpec => println!("{}", sess.target.to_json().pretty()),
                 FileNames | CrateName => {
                     let input = input.unwrap_or_else(|| {
                         early_error(ErrorOutputType::default(), "no input file provided")
@@ -1205,9 +1258,9 @@
     // If backtraces are enabled, also print the query stack
     let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
 
-    if backtrace {
-        TyCtxt::try_print_query_stack(&handler);
-    }
+    let num_frames = if backtrace { None } else { Some(2) };
+
+    TyCtxt::try_print_query_stack(&handler, num_frames);
 
     #[cfg(windows)]
     unsafe {
@@ -1241,11 +1294,21 @@
         Ok(s) if s.is_empty() => return,
         Ok(_) => {}
     }
-    let builder = tracing_subscriber::FmtSubscriber::builder();
+    let filter = tracing_subscriber::EnvFilter::from_env(env);
+    let layer = tracing_tree::HierarchicalLayer::default()
+        .with_indent_lines(true)
+        .with_ansi(true)
+        .with_targets(true)
+        .with_thread_ids(true)
+        .with_thread_names(true)
+        .with_wraparound(10)
+        .with_verbose_exit(true)
+        .with_verbose_entry(true)
+        .with_indent_amount(2);
 
-    let builder = builder.with_env_filter(tracing_subscriber::EnvFilter::from_env(env));
-
-    builder.init()
+    use tracing_subscriber::layer::SubscriberExt;
+    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+    tracing::subscriber::set_global_default(subscriber).unwrap();
 }
 
 pub fn main() -> ! {
@@ -1265,7 +1328,7 @@
                 })
             })
             .collect::<Vec<_>>();
-        run_compiler(&args, &mut callbacks, None, None)
+        RunCompiler::new(&args, &mut callbacks).run()
     });
     // The extra `\t` is necessary to align this label with the others.
     print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index a202736..0a88759 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -18,7 +18,6 @@
 E0013: include_str!("./error_codes/E0013.md"),
 E0014: include_str!("./error_codes/E0014.md"),
 E0015: include_str!("./error_codes/E0015.md"),
-E0019: include_str!("./error_codes/E0019.md"),
 E0023: include_str!("./error_codes/E0023.md"),
 E0025: include_str!("./error_codes/E0025.md"),
 E0026: include_str!("./error_codes/E0026.md"),
@@ -458,9 +457,15 @@
 E0771: include_str!("./error_codes/E0771.md"),
 E0773: include_str!("./error_codes/E0773.md"),
 E0774: include_str!("./error_codes/E0774.md"),
+E0775: include_str!("./error_codes/E0775.md"),
+E0776: include_str!("./error_codes/E0776.md"),
+E0777: include_str!("./error_codes/E0777.md"),
+E0778: include_str!("./error_codes/E0778.md"),
+E0779: include_str!("./error_codes/E0779.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
+//  E0019, merged into E0015
 //  E0035, merged into E0087/E0089
 //  E0036, merged into E0087/E0089
 //  E0068,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0007.md b/compiler/rustc_error_codes/src/error_codes/E0007.md
index 2be7870..2c22b86 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0007.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0007.md
@@ -1,3 +1,5 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 This error indicates that the bindings in a match arm would require a value to
 be moved into more than one location, thus violating unique ownership. Code
 like the following is invalid as it requires the entire `Option<String>` to be
@@ -6,11 +8,13 @@
 
 Erroneous code example:
 
-```compile_fail,E0007
+```compile_fail,E0382
+#![feature(bindings_after_at)]
+
 let x = Some("s".to_string());
 
 match x {
-    op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
+    op_string @ Some(s) => {}, // error: use of moved value
     None => {},
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0019.md b/compiler/rustc_error_codes/src/error_codes/E0019.md
deleted file mode 100644
index 7832468..0000000
--- a/compiler/rustc_error_codes/src/error_codes/E0019.md
+++ /dev/null
@@ -1,36 +0,0 @@
-A function call isn't allowed in the const's initialization expression
-because the expression's value must be known at compile-time.
-
-Erroneous code example:
-
-```compile_fail,E0019
-#![feature(box_syntax)]
-
-fn main() {
-    struct MyOwned;
-
-    static STATIC11: Box<MyOwned> = box MyOwned; // error!
-}
-```
-
-Remember: you can't use a function call inside a const's initialization
-expression! However, you can totally use it anywhere else:
-
-```
-enum Test {
-    V1
-}
-
-impl Test {
-    fn func(&self) -> i32 {
-        12
-    }
-}
-
-fn main() {
-    const FOO: Test = Test::V1;
-
-    FOO.func(); // here is good
-    let x = FOO.func(); // or even here!
-}
-```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0284.md b/compiler/rustc_error_codes/src/error_codes/E0284.md
index a1ffa2b..82598ae 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0284.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0284.md
@@ -5,37 +5,29 @@
 For example:
 
 ```compile_fail,E0284
-fn foo() -> Result<bool, ()> {
-    let results = [Ok(true), Ok(false), Err(())].iter().cloned();
-    let v: Vec<bool> = results.collect()?;
-    // Do things with v...
-    Ok(true)
+fn main() {
+    let n: u32 = 1;
+    let mut d: u64 = 2;
+    d = d + n.into();
 }
 ```
 
-Here we have an iterator `results` over `Result<bool, ()>`.
-Hence, `results.collect()` can return any type implementing
-`FromIterator<Result<bool, ()>>`. On the other hand, the
-`?` operator can accept any type implementing `Try`.
+Here we have an addition of `d` and `n.into()`. Hence, `n.into()` can return
+any type `T` where `u64: Add<T>`. On the other hand, the `into` method can
+return any type where `u32: Into<T>`.
 
-The author of this code probably wants `collect()` to return a
-`Result<Vec<bool>, ()>`, but the compiler can't be sure
-that there isn't another type `T` implementing both `Try` and
-`FromIterator<Result<bool, ()>>` in scope such that
-`T::Ok == Vec<bool>`. Hence, this code is ambiguous and an error
-is returned.
+The author of this code probably wants `into()` to return a `u64`, but the
+compiler can't be sure that there isn't another type `T` where both
+`u32: Into<T>` and `u64: Add<T>`.
 
 To resolve this error, use a concrete type for the intermediate expression:
 
 ```
-fn foo() -> Result<bool, ()> {
-    let results = [Ok(true), Ok(false), Err(())].iter().cloned();
-    let v = {
-        let temp: Result<Vec<bool>, ()> = results.collect();
-        temp?
-    };
-    // Do things with v...
-    Ok(true)
+fn main() {
+    let n: u32 = 1;
+    let mut d: u64 = 2;
+    let m: u64 = n.into();
+    d = d + m;
 }
 ```
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0424.md b/compiler/rustc_error_codes/src/error_codes/E0424.md
index a9f6f57..a58c16b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0424.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0424.md
@@ -21,7 +21,7 @@
 The `self` keyword can only be used inside methods, which are associated
 functions (functions defined inside of a `trait` or `impl` block) that have a
 `self` receiver as its first parameter, like `self`, `&self`, `&mut self` or
-`self: &mut Pin<Self>` (this last one is an example of an ["abitrary `self`
+`self: &mut Pin<Self>` (this last one is an example of an ["arbitrary `self`
 type"](https://github.com/rust-lang/rust/issues/44874)).
 
 Check if the associated function's parameter list should have contained a `self`
diff --git a/compiler/rustc_error_codes/src/error_codes/E0660.md b/compiler/rustc_error_codes/src/error_codes/E0660.md
index fccd1b9..26d35f2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0660.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0660.md
@@ -9,4 +9,4 @@
 Considering that this would be a long explanation, we instead recommend you
 take a look at the [`llvm_asm`] chapter of the Unstable book:
 
-[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
+[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0661.md b/compiler/rustc_error_codes/src/error_codes/E0661.md
index f1debee..0b8ba7f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0661.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0661.md
@@ -10,4 +10,4 @@
 Considering that this would be a long explanation, we instead recommend you
 take a look at the [`llvm_asm`] chapter of the Unstable book:
 
-[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
+[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0662.md b/compiler/rustc_error_codes/src/error_codes/E0662.md
index d4765f0..8c1bab8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0662.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0662.md
@@ -13,4 +13,4 @@
 Considering that this would be a long explanation, we instead recommend you
 take a look at the [`llvm_asm`] chapter of the Unstable book:
 
-[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
+[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0663.md b/compiler/rustc_error_codes/src/error_codes/E0663.md
index d5a85b2..53ffd33 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0663.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0663.md
@@ -13,4 +13,4 @@
 Considering that this would be a long explanation, we instead recommend you
 take a look at the [`llvm_asm`] chapter of the Unstable book:
 
-[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
+[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0664.md b/compiler/rustc_error_codes/src/error_codes/E0664.md
index ce9c949..f8e72cd 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0664.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0664.md
@@ -13,4 +13,4 @@
 Considering that this would be a long explanation, we instead recommend you
 take a look at the [`llvm_asm`] chapter of the Unstable book:
 
-[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
+[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0723.md b/compiler/rustc_error_codes/src/error_codes/E0723.md
index 95d47ab..bc22442 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0723.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0723.md
@@ -3,12 +3,8 @@
 Erroneous code example:
 
 ```compile_fail,E0723
-trait T {}
-
-impl T for () {}
-
-const fn foo() -> impl T { // error: `impl Trait` in const fn is unstable
-    ()
+const fn foo<T: Copy>(_: T) { // error!
+   // ...
 }
 ```
 
@@ -18,11 +14,7 @@
 ```
 #![feature(const_fn)]
 
-trait T {}
-
-impl T for () {}
-
-const fn foo() -> impl T {
-    ()
+const fn foo<T: Copy>(_: T) { // ok!
+   // ...
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md
new file mode 100644
index 0000000..9bafd52
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0775.md
@@ -0,0 +1,17 @@
+`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M
+extension.
+
+Erroneous code example:
+
+```compile_fail,E0775
+#![feature(cmse_nonsecure_entry)]
+
+#[cmse_nonsecure_entry]
+pub extern "C" fn entry_function() {}
+```
+
+To fix this error, compile your code for a Rust target that supports the
+TrustZone-M extension. The current possible targets are:
+* `thumbv8m.main-none-eabi`
+* `thumbv8m.main-none-eabihf`
+* `thumbv8m.base-none-eabi`
diff --git a/compiler/rustc_error_codes/src/error_codes/E0776.md b/compiler/rustc_error_codes/src/error_codes/E0776.md
new file mode 100644
index 0000000..d65beeb
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0776.md
@@ -0,0 +1,13 @@
+`#[cmse_nonsecure_entry]` functions require a C ABI
+
+Erroneous code example:
+
+```compile_fail,E0776
+#![feature(cmse_nonsecure_entry)]
+
+#[no_mangle]
+#[cmse_nonsecure_entry]
+pub fn entry_function(input: Vec<u32>) {}
+```
+
+To fix this error, declare your entry function with a C ABI, using `extern "C"`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0777.md b/compiler/rustc_error_codes/src/error_codes/E0777.md
new file mode 100644
index 0000000..8c5c6e2
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0777.md
@@ -0,0 +1,19 @@
+A literal value was used inside `#[derive]`.
+
+Erroneous code example:
+
+```compile_fail,E0777
+#[derive("Clone")] // error!
+struct Foo;
+```
+
+Only paths to traits are allowed as argument inside `#[derive]`. You can find
+more information about the `#[derive]` attribute in the [Rust Book].
+
+
+```
+#[derive(Clone)] // ok!
+struct Foo;
+```
+
+[Rust Book]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0778.md b/compiler/rustc_error_codes/src/error_codes/E0778.md
new file mode 100644
index 0000000..467362d
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0778.md
@@ -0,0 +1,35 @@
+The `instruction_set` attribute was malformed.
+
+Erroneous code example:
+
+```compile_fail,E0778
+#![feature(isa_attribute)]
+
+#[instruction_set()] // error: expected one argument
+pub fn something() {}
+fn main() {}
+```
+
+The parenthesized `instruction_set` attribute requires the parameter to be
+specified:
+
+```
+#![feature(isa_attribute)]
+
+#[cfg_attr(target_arch="arm", instruction_set(arm::a32))]
+fn something() {}
+```
+
+or:
+
+```
+#![feature(isa_attribute)]
+
+#[cfg_attr(target_arch="arm", instruction_set(arm::t32))]
+fn something() {}
+```
+
+For more information see the [`instruction_set` attribute][isa-attribute]
+section of the Reference.
+
+[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0779.md b/compiler/rustc_error_codes/src/error_codes/E0779.md
new file mode 100644
index 0000000..146e20c
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0779.md
@@ -0,0 +1,32 @@
+An unknown argument was given to the `instruction_set` attribute.
+
+Erroneous code example:
+
+```compile_fail,E0779
+#![feature(isa_attribute)]
+
+#[instruction_set(intel::x64)] // error: invalid argument
+pub fn something() {}
+fn main() {}
+```
+
+The `instruction_set` attribute only supports two arguments currently:
+
+ * arm::a32
+ * arm::t32
+
+All other arguments given to the `instruction_set` attribute will return this
+error. Example:
+
+```
+#![feature(isa_attribute)]
+
+#[cfg_attr(target_arch="arm", instruction_set(arm::a32))] // ok!
+pub fn something() {}
+fn main() {}
+```
+
+For more information see the [`instruction_set` attribute][isa-attribute]
+section of the Reference.
+
+[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 870f7b8..91bfc62 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -121,11 +121,6 @@
         self.level == Level::Cancelled
     }
 
-    /// Set the sorting span.
-    pub fn set_sort_span(&mut self, sp: Span) {
-        self.sort_span = sp;
-    }
-
     /// Adds a span/label to be included in the resulting snippet.
     ///
     /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic
@@ -535,14 +530,6 @@
         &self.message
     }
 
-    /// Used by a lint. Copies over all details *but* the "main
-    /// message".
-    pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
-        self.span = from.span.clone();
-        self.code = from.code.clone();
-        self.children.extend(from.children.iter().cloned())
-    }
-
     /// Convenience function for internal use, clients should use one of the
     /// public methods above.
     pub fn sub(
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 98cbf98..b5155f8 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -510,8 +510,6 @@
     fn emit_diagnostic(&mut self, _: &Diagnostic) {}
 }
 
-/// Maximum number of lines we will print for each error; arbitrary.
-pub const MAX_HIGHLIGHT_LINES: usize = 6;
 /// Maximum number of lines we will print for a multiline suggestion; arbitrary.
 ///
 /// This should be replaced with a more involved mechanism to output multiline suggestions that
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 926e3db..b0e43a2 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,10 +1,9 @@
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirectoryOwnership;
 
-use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::token;
-use rustc_ast::tokenstream::{self, TokenStream};
+use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, Attribute, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
@@ -149,17 +148,6 @@
         }
     }
 
-    pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable
-    where
-        F: FnMut(P<ast::Item>) -> P<ast::Item>,
-        G: FnMut(Annotatable) -> Annotatable,
-    {
-        match self {
-            Annotatable::Item(i) => Annotatable::Item(f(i)),
-            _ => or(self),
-        }
-    }
-
     pub fn expect_trait_item(self) -> P<ast::AssocItem> {
         match self {
             Annotatable::TraitItem(i) => i,
@@ -313,7 +301,7 @@
         ts: TokenStream,
     ) -> Result<TokenStream, ErrorReported> {
         // FIXME setup implicit context in TLS before calling self.
-        Ok((*self)(ts))
+        Ok(self(ts))
     }
 }
 
@@ -339,7 +327,7 @@
         annotated: TokenStream,
     ) -> Result<TokenStream, ErrorReported> {
         // FIXME setup implicit context in TLS before calling self.
-        Ok((*self)(annotation, annotated))
+        Ok(self(annotation, annotated))
     }
 }
 
@@ -364,31 +352,9 @@
         &self,
         ecx: &'cx mut ExtCtxt<'_>,
         span: Span,
-        mut input: TokenStream,
+        input: TokenStream,
     ) -> Box<dyn MacResult + 'cx> {
-        struct AvoidInterpolatedIdents;
-
-        impl MutVisitor for AvoidInterpolatedIdents {
-            fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) {
-                if let tokenstream::TokenTree::Token(token) = tt {
-                    if let token::Interpolated(nt) = &token.kind {
-                        if let token::NtIdent(ident, is_raw) = **nt {
-                            *tt = tokenstream::TokenTree::token(
-                                token::Ident(ident.name, is_raw),
-                                ident.span,
-                            );
-                        }
-                    }
-                }
-                mut_visit::noop_visit_tt(tt, self)
-            }
-
-            fn visit_mac(&mut self, mac: &mut ast::MacCall) {
-                mut_visit::noop_visit_mac(mac, self)
-            }
-        }
-        AvoidInterpolatedIdents.visit_tts(&mut input);
-        (*self)(ecx, span, input)
+        self(ecx, span, input)
     }
 }
 
@@ -1075,9 +1041,6 @@
             .chain(components.iter().map(|&s| Ident::with_dummy_span(s)))
             .collect()
     }
-    pub fn name_of(&self, st: &str) -> Symbol {
-        Symbol::intern(st)
-    }
 
     pub fn check_unused_macros(&mut self) {
         self.resolver.check_unused_macros();
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index a5a7ee6..1c9bfb9 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -139,24 +139,6 @@
         ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) }
     }
 
-    pub fn lifetime_def(
-        &self,
-        span: Span,
-        ident: Ident,
-        attrs: Vec<ast::Attribute>,
-        bounds: ast::GenericBounds,
-    ) -> ast::GenericParam {
-        let lifetime = self.lifetime(span, ident);
-        ast::GenericParam {
-            ident: lifetime.ident,
-            id: lifetime.id,
-            attrs: attrs.into(),
-            bounds,
-            kind: ast::GenericParamKind::Lifetime,
-            is_placeholder: false,
-        }
-    }
-
     pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
         ast::Stmt {
             id: ast::DUMMY_NODE_ID,
@@ -465,24 +447,6 @@
         self.pat_tuple_struct(span, path, vec![pat])
     }
 
-    pub fn pat_none(&self, span: Span) -> P<ast::Pat> {
-        let some = self.std_path(&[sym::option, sym::Option, sym::None]);
-        let path = self.path_global(span, some);
-        self.pat_path(span, path)
-    }
-
-    pub fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let some = self.std_path(&[sym::result, sym::Result, sym::Ok]);
-        let path = self.path_global(span, some);
-        self.pat_tuple_struct(span, path, vec![pat])
-    }
-
-    pub fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let some = self.std_path(&[sym::result, sym::Result, sym::Err]);
-        let path = self.path_global(span, some);
-        self.pat_tuple_struct(span, path, vec![pat])
-    }
-
     pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm {
         ast::Arm {
             attrs: vec![],
@@ -514,26 +478,6 @@
         self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els))
     }
 
-    pub fn lambda_fn_decl(
-        &self,
-        span: Span,
-        fn_decl: P<ast::FnDecl>,
-        body: P<ast::Expr>,
-        fn_decl_span: Span,
-    ) -> P<ast::Expr> {
-        self.expr(
-            span,
-            ast::ExprKind::Closure(
-                ast::CaptureBy::Ref,
-                ast::Async::No,
-                ast::Movability::Movable,
-                fn_decl,
-                body,
-                fn_decl_span,
-            ),
-        )
-    }
-
     pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: P<ast::Expr>) -> P<ast::Expr> {
         let fn_decl = self.fn_decl(
             ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(),
@@ -610,47 +554,6 @@
         })
     }
 
-    pub fn variant(&self, span: Span, ident: Ident, tys: Vec<P<ast::Ty>>) -> ast::Variant {
-        let vis_span = span.shrink_to_lo();
-        let fields: Vec<_> = tys
-            .into_iter()
-            .map(|ty| ast::StructField {
-                span: ty.span,
-                ty,
-                ident: None,
-                vis: ast::Visibility {
-                    span: vis_span,
-                    kind: ast::VisibilityKind::Inherited,
-                    tokens: None,
-                },
-                attrs: Vec::new(),
-                id: ast::DUMMY_NODE_ID,
-                is_placeholder: false,
-            })
-            .collect();
-
-        let vdata = if fields.is_empty() {
-            ast::VariantData::Unit(ast::DUMMY_NODE_ID)
-        } else {
-            ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID)
-        };
-
-        ast::Variant {
-            attrs: Vec::new(),
-            data: vdata,
-            disr_expr: None,
-            id: ast::DUMMY_NODE_ID,
-            ident,
-            vis: ast::Visibility {
-                span: vis_span,
-                kind: ast::VisibilityKind::Inherited,
-                tokens: None,
-            },
-            span,
-            is_placeholder: false,
-        }
-    }
-
     pub fn item_static(
         &self,
         span: Span,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e5cfb86..0b43225 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -18,9 +18,9 @@
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{struct_span_err, Applicability, PResult};
 use rustc_feature::Features;
-use rustc_parse::parser::Parser;
+use rustc_parse::parser::{AttemptLocalParseRecovery, Parser};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -542,7 +542,7 @@
     fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
         let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
         let span = attr.map_or(item.span(), |attr| attr.span);
-        let mut err = rustc_errors::struct_span_err!(
+        let mut err = struct_span_err!(
             self.cx.sess,
             span,
             E0774,
@@ -921,7 +921,7 @@
             let mut stmts = SmallVec::new();
             // Won't make progress on a `}`.
             while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) {
-                if let Some(stmt) = this.parse_full_stmt()? {
+                if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? {
                     stmts.push(stmt);
                 }
             }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f0e6fe3..791d268 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -288,7 +288,8 @@
                 // Replace all the tokens for the corresponding positions in the macro, to maintain
                 // proper positions in error reporting, while maintaining the macro_backtrace.
                 if rhs_spans.len() == tts.len() {
-                    tts = tts.map_enumerated(|i, mut tt| {
+                    tts = tts.map_enumerated(|i, tt| {
+                        let mut tt = tt.clone();
                         let mut sp = rhs_spans[i];
                         sp = sp.with_ctxt(tt.span().ctxt());
                         tt.set_span(sp);
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 94b3fcf..4c95f19 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -5,7 +5,8 @@
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_lexer::is_ident;
 use rustc_parse::nt_to_tokenstream;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
@@ -182,9 +183,22 @@
             .filter_map(|nmi| match nmi {
                 NestedMetaItem::Literal(lit) => {
                     error_reported_filter_map = true;
-                    cx.struct_span_err(lit.span, "expected path to a trait, found literal")
-                        .help("for example, write `#[derive(Debug)]` for `Debug`")
-                        .emit();
+                    let mut err = struct_span_err!(
+                        cx.sess,
+                        lit.span,
+                        E0777,
+                        "expected path to a trait, found literal",
+                    );
+                    let token = lit.token.to_string();
+                    if token.starts_with('"')
+                        && token.len() > 2
+                        && is_ident(&token[1..token.len() - 1])
+                    {
+                        err.help(&format!("try using `#[derive({})]`", &token[1..token.len() - 1]));
+                    } else {
+                        err.help("for example, write `#[derive(Debug)]` for `Debug`");
+                    }
+                    err.emit();
                     None
                 }
                 NestedMetaItem::MetaItem(mi) => Some(mi),
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 0477f6f..4401ec0 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -1,6 +1,6 @@
 //! List of the accepted feature gates.
 
-use super::{Feature, State};
+use super::{to_nonzero, Feature, State};
 use rustc_span::symbol::sym;
 
 macro_rules! declare_features {
@@ -14,7 +14,7 @@
                     state: State::Accepted,
                     name: sym::$feature,
                     since: $ver,
-                    issue: $issue,
+                    issue: to_nonzero($issue),
                     edition: None,
                     description: concat!($($doc,)*),
                 }
@@ -270,6 +270,9 @@
     (accepted, track_caller, "1.46.0", Some(47809), None),
     /// Allows `#[doc(alias = "...")]`.
     (accepted, doc_alias, "1.48.0", Some(50146), None),
+    /// Allows patterns with concurrent by-move and by-ref bindings.
+    /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
+    (accepted, move_ref_pattern, "1.48.0", Some(68354), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 17b9e1e..04912fe 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -1,6 +1,6 @@
 //! List of the active feature gates.
 
-use super::{Feature, State};
+use super::{to_nonzero, Feature, State};
 
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{sym, Symbol};
@@ -29,7 +29,7 @@
                     state: State::Active { set: set!($feature) },
                     name: sym::$feature,
                     since: $ver,
-                    issue: $issue,
+                    issue: to_nonzero($issue),
                     edition: $edition,
                     description: concat!($($doc,)*),
                 }
@@ -526,10 +526,6 @@
     /// For example, you can write `x @ Some(y)`.
     (active, bindings_after_at, "1.41.0", Some(65490), None),
 
-    /// Allows patterns with concurrent by-move and by-ref bindings.
-    /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
-    (active, move_ref_pattern, "1.42.0", Some(68354), None),
-
     /// Allows `impl const Trait for T` syntax.
     (active, const_trait_impl, "1.42.0", Some(67792), None),
 
@@ -581,12 +577,30 @@
     /// Allows `if let` guard in match arms.
     (active, if_let_guard, "1.47.0", Some(51114), None),
 
-    /// Allows non trivial generic constants which have to be manually propageted upwards.
+    /// Allows non-trivial generic constants which have to be manually propageted upwards.
     (active, const_evaluatable_checked, "1.48.0", Some(76560), None),
 
     /// Allows basic arithmetic on floating point types in a `const fn`.
     (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
 
+    /// Allows using and casting function pointers in a `const fn`.
+    (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
+
+    /// Allows to use the `#[cmse_nonsecure_entry]` attribute.
+    (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None),
+
+    /// Allows rustc to inject a default alloc_error_handler
+    (active, default_alloc_error_handler, "1.48.0", Some(66741), None),
+
+    /// Allows argument and return position `impl Trait` in a `const fn`.
+    (active, const_impl_trait, "1.48.0", Some(77463), None),
+
+    /// Allows `#[instruction_set(_)]` attribute
+    (active, isa_attribute, "1.48.0", Some(74727), None),
+
+    /// Allow anonymous constants from an inline `const` block
+    (active, inline_const, "1.49.0", Some(76001), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -607,6 +621,8 @@
     sym::const_trait_bound_opt_out,
     sym::lazy_normalization_consts,
     sym::specialization,
+    sym::inline_const,
+    sym::repr128,
 ];
 
 /// Some features are not allowed to be used together at the same time, if
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 8b7fd59..83aa1f6 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -336,6 +336,8 @@
         optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute,
         experimental!(optimize),
     ),
+    // RFC 2867
+    gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
 
     gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)),
     gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)),
@@ -349,6 +351,8 @@
         experimental!(register_tool),
     ),
 
+    gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)),
+
     // ==========================================================================
     // Internal attributes: Stability, deprecation, and unsafe:
     // ==========================================================================
@@ -464,7 +468,6 @@
     // ==========================================================================
 
     rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
-    rustc_attr!(rustc_allow_const_fn_ptr, AssumedUsed, template!(Word), IMPL_DETAIL),
     rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
 
     // ==========================================================================
@@ -595,7 +598,7 @@
     BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
 }
 
-pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &'static BuiltinAttribute>> =
+pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> =
     SyncLazy::new(|| {
         let mut map = FxHashMap::default();
         for attr in BUILTIN_ATTRIBUTES.iter() {
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 15564a5..68ac284 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -46,17 +46,11 @@
     pub state: State,
     pub name: Symbol,
     pub since: &'static str,
-    issue: Option<u32>, // FIXME: once #58732 is done make this an Option<NonZeroU32>
+    issue: Option<NonZeroU32>,
     pub edition: Option<Edition>,
     description: &'static str,
 }
 
-impl Feature {
-    fn issue(&self) -> Option<NonZeroU32> {
-        self.issue.and_then(NonZeroU32::new)
-    }
-}
-
 #[derive(Copy, Clone, Debug)]
 pub enum Stability {
     Unstable,
@@ -102,8 +96,8 @@
 fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
         // FIXME (#28244): enforce that active features have issue numbers
-        // assert!(info.issue().is_some())
-        info.issue()
+        // assert!(info.issue.is_some())
+        info.issue
     } else {
         // search in Accepted, Removed, or Stable Removed features
         let found = ACCEPTED_FEATURES
@@ -112,12 +106,21 @@
             .chain(STABLE_REMOVED_FEATURES)
             .find(|t| t.name == feature);
         match found {
-            Some(found) => found.issue(),
+            Some(found) => found.issue,
             None => panic!("feature `{}` is not declared anywhere", feature),
         }
     }
 }
 
+const fn to_nonzero(n: Option<u32>) -> Option<NonZeroU32> {
+    // Can be replaced with `n.and_then(NonZeroU32::new)` if that is ever usable
+    // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632.
+    match n {
+        None => None,
+        Some(n) => NonZeroU32::new(n),
+    }
+}
+
 pub enum GateIssue {
     Language,
     Library(Option<NonZeroU32>),
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 8d41089..a480ddc 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -1,6 +1,6 @@
 //! List of the removed feature gates.
 
-use super::{Feature, State};
+use super::{to_nonzero, Feature, State};
 use rustc_span::symbol::sym;
 
 macro_rules! declare_features {
@@ -14,7 +14,7 @@
                     state: State::Removed { reason: $reason },
                     name: sym::$feature,
                     since: $ver,
-                    issue: $issue,
+                    issue: to_nonzero($issue),
                     edition: None,
                     description: concat!($($doc,)*),
                 }
@@ -32,7 +32,7 @@
                     state: State::Stabilized { reason: None },
                     name: sym::$feature,
                     since: $ver,
-                    issue: $issue,
+                    issue: to_nonzero($issue),
                     edition: None,
                     description: concat!($($doc,)*),
                 }
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index 289b9f3..7742961 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -75,33 +75,6 @@
     }
 }
 
-#[derive(Debug)]
-pub enum RenameOrCopyRemove {
-    Rename,
-    CopyRemove,
-}
-
-/// Rename `p` into `q`, preferring to use `rename` if possible.
-/// If `rename` fails (rename may fail for reasons such as crossing
-/// filesystem), fallback to copy & remove
-pub fn rename_or_copy_remove<P: AsRef<Path>, Q: AsRef<Path>>(
-    p: P,
-    q: Q,
-) -> io::Result<RenameOrCopyRemove> {
-    let p = p.as_ref();
-    let q = q.as_ref();
-    match fs::rename(p, q) {
-        Ok(()) => Ok(RenameOrCopyRemove::Rename),
-        Err(_) => match fs::copy(p, q) {
-            Ok(_) => {
-                fs::remove_file(p)?;
-                Ok(RenameOrCopyRemove::CopyRemove)
-            }
-            Err(e) => Err(e),
-        },
-    }
-}
-
 #[cfg(unix)]
 pub fn path_to_c_string(p: &Path) -> CString {
     use std::ffi::OsStr;
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 96fde48..62b1254 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -341,9 +341,7 @@
 
     /// Returns an iterator over the items which are `Some`.
     pub fn present_items(self) -> impl Iterator<Item = T> {
-        use std::iter::once;
-
-        once(self.type_ns).chain(once(self.value_ns)).chain(once(self.macro_ns)).filter_map(|it| it)
+        IntoIter::new([self.type_ns, self.value_ns, self.macro_ns]).filter_map(|it| it)
     }
 }
 
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index afefde0..3f10937 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -118,7 +118,7 @@
 
         let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
 
-        ::std::mem::discriminant(data).hash(&mut hasher);
+        std::mem::discriminant(data).hash(&mut hasher);
         if let Some(name) = data.get_opt_name() {
             // Get a stable hash by considering the symbol chars rather than
             // the symbol index.
@@ -188,10 +188,6 @@
 }
 
 impl DefPath {
-    pub fn is_local(&self) -> bool {
-        self.krate == LOCAL_CRATE
-    }
-
     pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath
     where
         FN: FnMut(DefIndex) -> DefKey,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 636f67a..65b96da 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3,7 +3,6 @@
 crate use crate::hir_id::HirId;
 use crate::{itemlikevisit, LangItem};
 
-use rustc_ast::node_id::NodeMap;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
 use rustc_ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
@@ -306,10 +305,6 @@
         Self { args: &[], bindings: &[], parenthesized: false }
     }
 
-    pub fn is_empty(&self) -> bool {
-        self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized
-    }
-
     pub fn inputs(&self) -> &[Ty<'_>] {
         if self.parenthesized {
             for arg in self.args {
@@ -467,23 +462,6 @@
         }
     }
 
-    pub fn own_counts(&self) -> GenericParamCount {
-        // We could cache this as a property of `GenericParamCount`, but
-        // the aim is to refactor this away entirely eventually and the
-        // presence of this method will be a constant reminder.
-        let mut own_counts: GenericParamCount = Default::default();
-
-        for param in self.params {
-            match param.kind {
-                GenericParamKind::Lifetime { .. } => own_counts.lifetimes += 1,
-                GenericParamKind::Type { .. } => own_counts.types += 1,
-                GenericParamKind::Const { .. } => own_counts.consts += 1,
-            };
-        }
-
-        own_counts
-    }
-
     pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> {
         for param in self.params {
             if name == param.name.ident().name {
@@ -1383,6 +1361,7 @@
     pub fn precedence(&self) -> ExprPrecedence {
         match self.kind {
             ExprKind::Box(_) => ExprPrecedence::Box,
+            ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
             ExprKind::Array(_) => ExprPrecedence::Array,
             ExprKind::Call(..) => ExprPrecedence::Call,
             ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
@@ -1468,6 +1447,7 @@
             | ExprKind::LlvmInlineAsm(..)
             | ExprKind::AssignOp(..)
             | ExprKind::Lit(_)
+            | ExprKind::ConstBlock(..)
             | ExprKind::Unary(..)
             | ExprKind::Box(..)
             | ExprKind::AddrOf(..)
@@ -1523,6 +1503,8 @@
 pub enum ExprKind<'hir> {
     /// A `box x` expression.
     Box(&'hir Expr<'hir>),
+    /// Allow anonymous constants from an inline `const` block
+    ConstBlock(AnonConst),
     /// An array (e.g., `[a, b, c, d]`).
     Array(&'hir [Expr<'hir>]),
     /// A function call.
@@ -2399,15 +2381,6 @@
             VisibilityKind::Crate(..) | VisibilityKind::Restricted { .. } => true,
         }
     }
-
-    pub fn descr(&self) -> &'static str {
-        match *self {
-            VisibilityKind::Public => "public",
-            VisibilityKind::Inherited => "private",
-            VisibilityKind::Crate(..) => "crate-visible",
-            VisibilityKind::Restricted { .. } => "restricted",
-        }
-    }
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -2679,8 +2652,6 @@
     pub span: Span,
 }
 
-pub type CaptureModeMap = NodeMap<CaptureBy>;
-
 // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
 // has length > 0 if the trait is found through an chain of imports, starting with the
 // import/use statement in the scope where the trait is used.
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index fea850c..cc8ac4c 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -45,5 +45,3 @@
     owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
     local_id: ItemLocalId::from_u32(0),
 };
-
-pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX;
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 820d664..35615af 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1068,6 +1068,7 @@
         ExprKind::Array(subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }
+        ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
         ExprKind::Repeat(ref element, ref count) => {
             visitor.visit_expr(element);
             visitor.visit_anon_const(count)
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index 2f1b5da..c05d3e4 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -58,25 +58,6 @@
 }
 
 impl hir::Pat<'_> {
-    pub fn is_refutable(&self) -> bool {
-        match self.kind {
-            PatKind::Lit(_)
-            | PatKind::Range(..)
-            | PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => {
-                true
-            }
-
-            PatKind::Path(hir::QPath::Resolved(_, ref path))
-            | PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..)
-            | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => match path.res {
-                Res::Def(DefKind::Variant, _) => true,
-                _ => false,
-            },
-            PatKind::Slice(..) => true,
-            _ => false,
-        }
-    }
-
     /// Call `f` on every "binding" in a pattern, e.g., on `a` in
     /// `match foo() { Some(a) => (), None => () }`
     pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) {
@@ -117,15 +98,6 @@
         })
     }
 
-    /// Checks if the pattern contains any patterns that bind something to
-    /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
-    pub fn contains_bindings_or_wild(&self) -> bool {
-        self.satisfies(|p| match p.kind {
-            PatKind::Binding(..) | PatKind::Wild => true,
-            _ => false,
-        })
-    }
-
     /// Checks if the pattern satisfies the given predicate on some sub-pattern.
     fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool {
         let mut satisfies = false;
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 1efc8bc..fd6a312 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -9,13 +9,13 @@
 
 use std::fmt::{self, Display};
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum MethodKind {
     Trait { body: bool },
     Inherent,
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum Target {
     ExternCrate,
     Use,
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index f6e4b1f..1cd4dda 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -44,9 +44,6 @@
     fn nested(&self, _state: &mut State<'_>, _nested: Nested) {}
     fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
     fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
-    fn try_fetch_item(&self, _: hir::HirId) -> Option<&hir::Item<'_>> {
-        None
-    }
 }
 
 pub struct NoAnn;
@@ -54,9 +51,6 @@
 pub const NO_ANN: &dyn PpAnn = &NoAnn;
 
 impl PpAnn for hir::Crate<'_> {
-    fn try_fetch_item(&self, item: hir::HirId) -> Option<&hir::Item<'_>> {
-        Some(self.item(item))
-    }
     fn nested(&self, state: &mut State<'_>, nested: Nested) {
         match nested {
             Nested::Item(id) => state.print_item(self.item(id.id)),
@@ -141,6 +135,9 @@
 }
 
 impl<'a> PrintState<'a> for State<'a> {
+    fn insert_extra_parens(&self) -> bool {
+        true
+    }
     fn comments(&mut self) -> &mut Option<Comments<'a>> {
         &mut self.comments
     }
@@ -1138,6 +1135,13 @@
         self.end()
     }
 
+    fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
+        self.ibox(INDENT_UNIT);
+        self.s.word_space("const");
+        self.print_anon_const(anon_const);
+        self.end()
+    }
+
     fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
         self.ibox(INDENT_UNIT);
         self.s.word("[");
@@ -1290,6 +1294,9 @@
             hir::ExprKind::Array(ref exprs) => {
                 self.print_expr_vec(exprs);
             }
+            hir::ExprKind::ConstBlock(ref anon_const) => {
+                self.print_expr_anon_const(anon_const);
+            }
             hir::ExprKind::Repeat(ref element, ref count) => {
                 self.print_expr_repeat(&element, count);
             }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index a540fac..6a1715e 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -35,7 +35,7 @@
 use crate::traits::{Obligation, PredicateObligations};
 
 use rustc_ast as ast;
-use rustc_data_structures::mini_map::MiniMap;
+use rustc_data_structures::sso::SsoHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
@@ -429,7 +429,7 @@
             needs_wf: false,
             root_ty: ty,
             param_env: self.param_env,
-            cache: MiniMap::new(),
+            cache: SsoHashMap::new(),
         };
 
         let ty = match generalize.relate(ty, ty) {
@@ -490,7 +490,7 @@
 
     param_env: ty::ParamEnv<'tcx>,
 
-    cache: MiniMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
+    cache: SsoHashMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
 }
 
 /// Result from a generalization operation. This includes
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 795c5a6..3a0ec63 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -619,6 +619,7 @@
                 scrut_hir_id,
                 opt_suggest_box_span,
                 arm_span,
+                scrut_span,
                 ..
             }) => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
@@ -664,18 +665,29 @@
                         Some(ty::error::ExpectedFound { expected, .. }) => expected,
                         _ => last_ty,
                     });
-                    let msg = "`match` arms have incompatible types";
-                    err.span_label(cause.span, msg);
+                    let source_map = self.tcx.sess.source_map();
+                    let mut any_multiline_arm = source_map.is_multiline(arm_span);
                     if prior_arms.len() <= 4 {
                         for sp in prior_arms {
+                            any_multiline_arm |= source_map.is_multiline(*sp);
                             err.span_label(*sp, format!("this is found to be of type `{}`", t));
                         }
                     } else if let Some(sp) = prior_arms.last() {
+                        any_multiline_arm |= source_map.is_multiline(*sp);
                         err.span_label(
                             *sp,
                             format!("this and all prior arms are found to be of type `{}`", t),
                         );
                     }
+                    let outer_error_span = if any_multiline_arm {
+                        // Cover just `match` and the scrutinee expression, not
+                        // the entire match body, to reduce diagram noise.
+                        cause.span.shrink_to_lo().to(scrut_span)
+                    } else {
+                        cause.span
+                    };
+                    let msg = "`match` arms have incompatible types";
+                    err.span_label(outer_error_span, msg);
                     if let Some(sp) = semi_span {
                         err.span_suggestion_short(
                             sp,
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 2f3089f..21023a0 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
@@ -91,17 +91,6 @@
         if let (None, Some(ty)) =
             (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
         {
-            // FIXME: There's a trade-off here - we can either check that our target span
-            // is contained in `local.span` or not. If we choose to check containment
-            // we can avoid some spurious suggestions (see #72690), but we lose
-            // the ability to report on things like:
-            //
-            // ```
-            // let x = vec![];
-            // ```
-            //
-            // because the target span will be in the macro expansion of `vec![]`.
-            // At present we choose not to check containment.
             self.found_local_pattern = Some(&*local.pat);
             self.found_node_ty = Some(ty);
         }
@@ -113,10 +102,8 @@
             if let (None, Some(ty)) =
                 (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
             {
-                if self.target_span.contains(param.pat.span) {
-                    self.found_arg_pattern = Some(&*param.pat);
-                    self.found_node_ty = Some(ty);
-                }
+                self.found_arg_pattern = Some(&*param.pat);
+                self.found_node_ty = Some(ty);
             }
         }
         intravisit::walk_body(self, body);
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index ffe5fb1..32f7323 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -157,7 +157,7 @@
 
 impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
     type Lifted = FreeRegionMap<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
-        self.relation.maybe_map(|&fr| tcx.lift(&fr)).map(|relation| FreeRegionMap { relation })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
+        self.relation.maybe_map(|&fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
     }
 }
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index ea19dff..e3365e8 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -2,7 +2,7 @@
 //! the end of the file for details.
 
 use super::combine::CombineFields;
-use super::{HigherRankedType, InferCtxt, PlaceholderMap};
+use super::{HigherRankedType, InferCtxt};
 
 use crate::infer::CombinedSnapshot;
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -33,7 +33,7 @@
         self.infcx.commit_if_ok(|_| {
             // First, we instantiate each bound region in the supertype with a
             // fresh placeholder region.
-            let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(&b);
+            let b_prime = self.infcx.replace_bound_vars_with_placeholders(&b);
 
             // Next, we instantiate each bound region in the subtype
             // with a fresh region variable. These region variables --
@@ -66,10 +66,7 @@
     /// the [rustc dev guide].
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-    pub fn replace_bound_vars_with_placeholders<T>(
-        &self,
-        binder: &ty::Binder<T>,
-    ) -> (T, PlaceholderMap<'tcx>)
+    pub fn replace_bound_vars_with_placeholders<T>(&self, binder: &ty::Binder<T>) -> T
     where
         T: TypeFoldable<'tcx>,
     {
@@ -122,7 +119,7 @@
             next_universe, binder, result, map,
         );
 
-        (result, map)
+        result
     }
 
     /// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 07a55c7..ff7bbf0 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -113,13 +113,6 @@
 }
 
 impl RegionckMode {
-    pub fn suppressed(self) -> bool {
-        match self {
-            Self::Solve => false,
-            Self::Erase { suppress_errors } => suppress_errors,
-        }
-    }
-
     /// Indicates that the MIR borrowck will repeat these region
     /// checks, so we should ignore errors if NLL is (unconditionally)
     /// enabled.
@@ -351,11 +344,6 @@
     universe: Cell<ty::UniverseIndex>,
 }
 
-/// A map returned by `replace_bound_vars_with_placeholders()`
-/// indicating the placeholder region that each late-bound region was
-/// replaced with.
-pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
-
 /// See the `error_reporting` module for more details.
 #[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)]
 pub enum ValuePairs<'tcx> {
@@ -425,15 +413,6 @@
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(SubregionOrigin<'_>, 32);
 
-/// Places that type/region parameters can appear.
-#[derive(Clone, Copy, Debug)]
-pub enum ParameterOrigin {
-    Path,               // foo::bar
-    MethodCall,         // foo.bar() <-- parameters on impl providing bar()
-    OverloadedOperator, // a + b when overloaded
-    OverloadedDeref,    // *a when overloaded
-}
-
 /// Times when we replace late-bound regions with variables:
 #[derive(Clone, Copy, Debug)]
 pub enum LateBoundRegionConversionTime {
@@ -513,21 +492,6 @@
     },
 }
 
-impl NLLRegionVariableOrigin {
-    pub fn is_universal(self) -> bool {
-        match self {
-            NLLRegionVariableOrigin::FreeRegion => true,
-            NLLRegionVariableOrigin::Placeholder(..) => true,
-            NLLRegionVariableOrigin::Existential { .. } => false,
-            NLLRegionVariableOrigin::RootEmptyRegion => false,
-        }
-    }
-
-    pub fn is_existential(self) -> bool {
-        !self.is_universal()
-    }
-}
-
 // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
 #[derive(Copy, Clone, Debug)]
 pub enum FixupError<'tcx> {
@@ -992,7 +956,7 @@
         }
 
         Some(self.commit_if_ok(|_snapshot| {
-            let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
+            let ty::SubtypePredicate { a_is_expected, a, b } =
                 self.replace_bound_vars_with_placeholders(&predicate);
 
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
@@ -1007,7 +971,7 @@
         predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
     ) -> UnitResult<'tcx> {
         self.commit_if_ok(|_snapshot| {
-            let (ty::OutlivesPredicate(r_a, r_b), _) =
+            let ty::OutlivesPredicate(r_a, r_b) =
                 self.replace_bound_vars_with_placeholders(&predicate);
             let origin = SubregionOrigin::from_obligation_cause(cause, || {
                 RelateRegionParamBound(cause.span)
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 839891f..abdd6ed 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -28,7 +28,6 @@
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::subst::GenericArg;
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
 use std::fmt::Debug;
 
@@ -119,12 +118,6 @@
     fn forbid_inference_vars() -> bool;
 }
 
-#[derive(Clone, Debug)]
-struct ScopesAndKind<'tcx> {
-    scopes: Vec<BoundRegionScope<'tcx>>,
-    kind: GenericArg<'tcx>,
-}
-
 #[derive(Clone, Debug, Default)]
 struct BoundRegionScope<'tcx> {
     map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
@@ -341,7 +334,7 @@
         // been fully instantiated and hence the set of scopes we have
         // doesn't matter -- just to be sure, put an empty vector
         // in there.
-        let old_a_scopes = ::std::mem::take(pair.vid_scopes(self));
+        let old_a_scopes = std::mem::take(pair.vid_scopes(self));
 
         // Relate the generalized kind to the original one.
         let result = pair.relate_generalized_ty(self, generalized_ty);
@@ -643,7 +636,7 @@
         if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
             // Fast path for the common case.
             self.relate(a, b)?;
-            return Ok(ty::Binder::bind(a));
+            return Ok(ty::Binder::dummy(a));
         }
 
         if self.ambient_covariance() {
@@ -680,7 +673,7 @@
             //   itself occurs. Note that `'b` and `'c` must both
             //   include P. At the point, the call works because of
             //   subtyping (i.e., `&'b u32 <: &{P} u32`).
-            let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
+            let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
 
             self.relate(a.skip_binder(), b.skip_binder())?;
 
@@ -709,7 +702,7 @@
             // Reset ambient variance to contravariance. See the
             // covariant case above for an explanation.
             let variance =
-                ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
+                std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
 
             self.relate(a.skip_binder(), b.skip_binder())?;
 
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 2851da8..eb1a780 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -110,7 +110,7 @@
 
     /// Trait queries just want to pass back type obligations "as is"
     pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> {
-        ::std::mem::take(&mut self.inner.borrow_mut().region_obligations)
+        std::mem::take(&mut self.inner.borrow_mut().region_obligations)
     }
 
     /// Process the region obligations that must be proven (during
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 21b0836..2b827f4 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -1,7 +1,7 @@
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::{GenericKind, VerifyBound};
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::mini_set::MiniSet;
+use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -32,7 +32,7 @@
     /// Returns a "verify bound" that encodes what we know about
     /// `generic` and the regions it outlives.
     pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
-        let mut visited = MiniSet::new();
+        let mut visited = SsoHashSet::new();
         match generic {
             GenericKind::Param(param_ty) => self.param_bound(param_ty),
             GenericKind::Projection(projection_ty) => {
@@ -44,7 +44,7 @@
     fn type_bound(
         &self,
         ty: Ty<'tcx>,
-        visited: &mut MiniSet<GenericArg<'tcx>>,
+        visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> VerifyBound<'tcx> {
         match *ty.kind() {
             ty::Param(p) => self.param_bound(p),
@@ -148,7 +148,7 @@
     pub fn projection_bound(
         &self,
         projection_ty: ty::ProjectionTy<'tcx>,
-        visited: &mut MiniSet<GenericArg<'tcx>>,
+        visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> VerifyBound<'tcx> {
         debug!("projection_bound(projection_ty={:?})", projection_ty);
 
@@ -186,7 +186,7 @@
     fn recursive_bound(
         &self,
         parent: GenericArg<'tcx>,
-        visited: &mut MiniSet<GenericArg<'tcx>>,
+        visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> VerifyBound<'tcx> {
         let mut bounds = parent
             .walk_shallow(visited)
@@ -328,8 +328,8 @@
         assoc_item_def_id: DefId,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let predicates = tcx.projection_predicates(assoc_item_def_id);
-        predicates
+        let bounds = tcx.item_bounds(assoc_item_def_id);
+        bounds
             .into_iter()
             .filter_map(|p| p.to_opt_type_outlives())
             .filter_map(|p| p.no_bound_vars())
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index f873358..835f75e 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -2,12 +2,12 @@
 
 use crate::infer::InferCtxt;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{MultiSpan, Span};
 use std::fmt;
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -54,10 +54,11 @@
         "the trait `{}` cannot be made into an object",
         trait_str
     );
-    err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
+    err.span_label(span, format!("`{}` cannot be made into an object", trait_str));
 
     let mut reported_violations = FxHashSet::default();
-    let mut had_span_label = false;
+    let mut multi_span = vec![];
+    let mut messages = vec![];
     for violation in violations {
         if let ObjectSafetyViolation::SizedSelf(sp) = &violation {
             if !sp.is_empty() {
@@ -71,31 +72,37 @@
             let msg = if trait_span.is_none() || spans.is_empty() {
                 format!("the trait cannot be made into an object because {}", violation.error_msg())
             } else {
-                had_span_label = true;
                 format!("...because {}", violation.error_msg())
             };
             if spans.is_empty() {
                 err.note(&msg);
             } else {
                 for span in spans {
-                    err.span_label(span, &msg);
+                    multi_span.push(span);
+                    messages.push(msg.clone());
                 }
             }
-            match (trait_span, violation.solution()) {
-                (Some(_), Some((note, None))) => {
-                    err.help(&note);
-                }
-                (Some(_), Some((note, Some((sugg, span))))) => {
-                    err.span_suggestion(span, &note, sugg, Applicability::MachineApplicable);
-                }
+            if trait_span.is_some() {
                 // Only provide the help if its a local trait, otherwise it's not actionable.
-                _ => {}
+                violation.solution(&mut err);
             }
         }
     }
-    if let (Some(trait_span), true) = (trait_span, had_span_label) {
-        err.span_label(trait_span, "this trait cannot be made into an object...");
+    let has_multi_span = !multi_span.is_empty();
+    let mut note_span = MultiSpan::from_spans(multi_span.clone());
+    if let (Some(trait_span), true) = (trait_span, has_multi_span) {
+        note_span
+            .push_span_label(trait_span, "this trait cannot be made into an object...".to_string());
     }
+    for (span, msg) in multi_span.into_iter().zip(messages.into_iter()) {
+        note_span.push_span_label(span, msg);
+    }
+    err.span_note(
+        note_span,
+        "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \
+         to be resolvable dynamically; for more information visit \
+         <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+    );
 
     if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
         // Avoid emitting error caused by non-existing method (#58734)
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 7e7c858..aaf5e95 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -57,11 +57,9 @@
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateObligation<'_>, 40);
+static_assert_size!(PredicateObligation<'_>, 32);
 
-pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
-pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
 
 pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>;
 
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 9c0d934..f6ef984 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -4,7 +4,6 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
-use rustc_span::Span;
 
 pub fn anonymize_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -94,7 +93,11 @@
     tcx: TyCtxt<'tcx>,
     predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
 ) -> Elaborator<'tcx> {
-    let obligations = predicates.map(|predicate| predicate_obligation(predicate, None)).collect();
+    let obligations = predicates
+        .map(|predicate| {
+            predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy())
+        })
+        .collect();
     elaborate_obligations(tcx, obligations)
 }
 
@@ -109,15 +112,10 @@
 
 fn predicate_obligation<'tcx>(
     predicate: ty::Predicate<'tcx>,
-    span: Option<Span>,
+    param_env: ty::ParamEnv<'tcx>,
+    cause: ObligationCause<'tcx>,
 ) -> PredicateObligation<'tcx> {
-    let cause = if let Some(span) = span {
-        ObligationCause::dummy_with_span(span)
-    } else {
-        ObligationCause::dummy()
-    };
-
-    Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }
+    Obligation { cause, param_env, recursion_depth: 0, predicate }
 }
 
 impl Elaborator<'tcx> {
@@ -128,15 +126,17 @@
     fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
         let tcx = self.visited.tcx;
 
-        match obligation.predicate.skip_binders() {
+        let bound_predicate = obligation.predicate.bound_atom();
+        match bound_predicate.skip_binder() {
             ty::PredicateAtom::Trait(data, _) => {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
-                let obligations = predicates.predicates.iter().map(|&(pred, span)| {
+                let obligations = predicates.predicates.iter().map(|&(pred, _)| {
                     predicate_obligation(
-                        pred.subst_supertrait(tcx, &ty::Binder::bind(data.trait_ref)),
-                        Some(span),
+                        pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
+                        obligation.param_env,
+                        obligation.cause.clone(),
                     )
                 });
                 debug!("super_predicates: data={:?}", data);
@@ -233,7 +233,13 @@
                         })
                         .map(|predicate_kind| predicate_kind.to_predicate(tcx))
                         .filter(|&predicate| visited.insert(predicate))
-                        .map(|predicate| predicate_obligation(predicate, None)),
+                        .map(|predicate| {
+                            predicate_obligation(
+                                predicate,
+                                obligation.param_env,
+                                obligation.cause.clone(),
+                            )
+                        }),
                 );
             }
             ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 4d84462..73a51ad 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -154,6 +154,10 @@
     pub override_queries:
         Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
 
+    /// This is a callback from the driver that is called to create a codegen backend.
+    pub make_codegen_backend:
+        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
+
     /// Registry of diagnostics codes.
     pub registry: Registry,
 }
@@ -167,6 +171,7 @@
         config.file_loader,
         config.input_path.clone(),
         config.lint_caps,
+        config.make_codegen_backend,
         registry.clone(),
     );
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 66d3765..d9c24cc 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -551,6 +551,10 @@
             .map(|fmap| escape_dep_filename(&fmap.unmapped_path.as_ref().unwrap_or(&fmap.name)))
             .collect();
 
+        if let Some(ref backend) = sess.opts.debugging_opts.codegen_backend {
+            files.push(backend.to_string());
+        }
+
         if sess.binary_dep_depinfo() {
             boxed_resolver.borrow().borrow_mut().access(|resolver| {
                 for cnum in resolver.cstore().crates_untracked() {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 8b82217..1de7350 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -3,6 +3,7 @@
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -13,7 +14,8 @@
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
-use rustc_session::config::{OutputFilenames, OutputType};
+use rustc_serialize::json;
+use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::{output::find_crate_name, Session};
 use rustc_span::symbol::sym;
 use std::any::Any;
@@ -331,6 +333,7 @@
     pub fn linker(&'tcx self) -> Result<Linker> {
         let dep_graph = self.dep_graph()?;
         let prepare_outputs = self.prepare_outputs()?;
+        let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
         let ongoing_codegen = self.ongoing_codegen()?;
 
         let sess = self.session().clone();
@@ -340,6 +343,7 @@
             sess,
             dep_graph: dep_graph.peek().clone(),
             prepare_outputs: prepare_outputs.take(),
+            crate_hash,
             ongoing_codegen: ongoing_codegen.take(),
             codegen_backend,
         })
@@ -350,18 +354,31 @@
     sess: Lrc<Session>,
     dep_graph: DepGraph,
     prepare_outputs: OutputFilenames,
+    crate_hash: Svh,
     ongoing_codegen: Box<dyn Any>,
     codegen_backend: Lrc<Box<dyn CodegenBackend>>,
 }
 
 impl Linker {
     pub fn link(self) -> Result<()> {
-        let codegen_results =
-            self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess, &self.dep_graph)?;
-        let prof = self.sess.prof.clone();
+        let (codegen_results, work_products) =
+            self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess)?;
+
+        self.sess.compile_status()?;
+
+        let sess = &self.sess;
         let dep_graph = self.dep_graph;
+        sess.time("serialize_work_products", || {
+            rustc_incremental::save_work_product_index(&sess, &dep_graph, work_products)
+        });
+
+        let prof = self.sess.prof.clone();
         prof.generic_activity("drop_dep_graph").run(move || drop(dep_graph));
 
+        // Now that we won't touch anything in the incremental compilation directory
+        // any more, we can finalize it (which involves renaming it)
+        rustc_incremental::finalize_session_directory(&self.sess, self.crate_hash);
+
         if !self
             .sess
             .opts
@@ -371,6 +388,19 @@
         {
             return Ok(());
         }
+
+        if sess.opts.debugging_opts.no_link {
+            // FIXME: use a binary format to encode the `.rlink` file
+            let rlink_data = json::encode(&codegen_results).map_err(|err| {
+                sess.fatal(&format!("failed to encode rlink: {}", err));
+            })?;
+            let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
+            std::fs::write(&rlink_file, rlink_data).map_err(|err| {
+                sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
+            })?;
+            return Ok(());
+        }
+
         self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs)
     }
 }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 72e10bc..6553d0e 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -568,6 +568,7 @@
     tracked!(osx_rpath_install_name, true);
     tracked!(panic_abort_tests, true);
     tracked!(plt, Some(true));
+    tracked!(precise_enum_drop_elaboration, false);
     tracked!(print_fuel, Some("abc".to_string()));
     tracked!(profile, true);
     tracked!(profile_emit, Some(PathBuf::from("abc")));
@@ -584,6 +585,7 @@
     tracked!(symbol_mangling_version, SymbolManglingVersion::V0);
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
+    tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(treat_err_as_bug, Some(1));
     tracked!(unleash_the_miri_inside_of_you, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 0eed693..c1b359c 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -63,9 +63,17 @@
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     input_path: Option<PathBuf>,
     lint_caps: FxHashMap<lint::LintId, lint::Level>,
+    make_codegen_backend: Option<
+        Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+    >,
     descriptions: Registry,
 ) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) {
-    let codegen_backend = get_codegen_backend(&sopts);
+    let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
+        make_codegen_backend(&sopts)
+    } else {
+        get_codegen_backend(&sopts)
+    };
+
     // target_override is documented to be called before init(), so this is okay
     let target_override = codegen_backend.target_override(&sopts);
 
@@ -179,7 +187,7 @@
         config = config.stack_size(size);
     }
 
-    let with_pool = move |pool: &rayon::ThreadPool| pool.install(move || f());
+    let with_pool = move |pool: &rayon::ThreadPool| pool.install(f);
 
     rustc_span::with_session_globals(edition, || {
         rustc_span::SESSION_GLOBALS.with(|session_globals| {
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index d784a86..c5b59a0 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -48,6 +48,7 @@
 }
 
 /// Enum representing common lexeme types.
+// perf note: Changing all `usize` to `u32` doesn't change performance. See #77629
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum TokenKind {
     // Multi-char tokens:
@@ -160,6 +161,7 @@
 /// - `r##~"abcde"##`: `InvalidStarter`
 /// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
 /// - Too many `#`s (>65535): `TooManyDelimiters`
+// perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum RawStrError {
     /// Non `#` characters exist between `r` and `"` eg. `r#~"..`
@@ -689,7 +691,12 @@
         let mut max_hashes = 0;
 
         // Count opening '#' symbols.
-        let n_start_hashes = self.eat_while(|c| c == '#');
+        let mut eaten = 0;
+        while self.first() == '#' {
+            eaten += 1;
+            self.bump();
+        }
+        let n_start_hashes = eaten;
 
         // Check that string is started.
         match self.bump() {
@@ -724,16 +731,11 @@
             // Note that this will not consume extra trailing `#` characters:
             // `r###"abcde"####` is lexed as a `RawStr { n_hashes: 3 }`
             // followed by a `#` token.
-            let mut hashes_left = n_start_hashes;
-            let is_closing_hash = |c| {
-                if c == '#' && hashes_left != 0 {
-                    hashes_left -= 1;
-                    true
-                } else {
-                    false
-                }
-            };
-            let n_end_hashes = self.eat_while(is_closing_hash);
+            let mut n_end_hashes = 0;
+            while self.first() == '#' && n_end_hashes < n_start_hashes {
+                n_end_hashes += 1;
+                self.bump();
+            }
 
             if n_end_hashes == n_start_hashes {
                 return (n_start_hashes, None);
@@ -807,17 +809,9 @@
     }
 
     /// Eats symbols while predicate returns true or until the end of file is reached.
-    /// Returns amount of eaten symbols.
-    fn eat_while<F>(&mut self, mut predicate: F) -> usize
-    where
-        F: FnMut(char) -> bool,
-    {
-        let mut eaten: usize = 0;
+    fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
         while predicate(self.first()) && !self.is_eof() {
-            eaten += 1;
             self.bump();
         }
-
-        eaten
     }
 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index abd899e..a964950 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -968,7 +968,7 @@
     while let Some(attr) = attrs.next() {
         if attr.is_doc_comment() {
             sugared_span =
-                Some(sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi())));
+                Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
         }
 
         if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() {
@@ -2288,12 +2288,20 @@
                             n, n,
                         ));
                     }
+                    if HAS_MIN_FEATURES.contains(&name) {
+                        builder.help(&format!(
+                            "consider using `min_{}` instead, which is more stable and complete",
+                            name,
+                        ));
+                    }
                     builder.emit();
                 })
             });
     }
 }
 
+const HAS_MIN_FEATURES: &[Symbol] = &[sym::const_generics, sym::specialization];
+
 declare_lint! {
     /// The `invalid_value` lint detects creating a value that is not valid,
     /// such as a NULL reference.
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 7a3035e..48270eb 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -711,10 +711,6 @@
         }
     }
 
-    pub fn current_lint_root(&self) -> hir::HirId {
-        self.last_node_with_lint_attrs
-    }
-
     /// Check if a `DefId`'s path matches the given absolute type path usage.
     ///
     /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 998676d..4c8baa4 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -195,6 +195,11 @@
         run_early_pass!(self, check_expr_post, e);
     }
 
+    fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) {
+        run_early_pass!(self, check_generic_arg, arg);
+        ast_visit::walk_generic_arg(self, arg);
+    }
+
     fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
         run_early_pass!(self, check_generic_param, param);
         ast_visit::walk_generic_param(self, param);
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 48254dc..222333a 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -10,6 +10,7 @@
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_hir::{intravisit, HirId};
 use rustc_middle::hir::map::Map;
+use rustc_middle::lint::LevelSource;
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
 use rustc_middle::ty::query::Providers;
@@ -95,6 +96,44 @@
         self.sets.list.push(LintSet::CommandLine { specs });
     }
 
+    /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
+    /// (e.g. if a forbid was already inserted on the same scope), then emits a
+    /// diagnostic with no change to `specs`.
+    fn insert_spec(
+        &mut self,
+        specs: &mut FxHashMap<LintId, LevelSource>,
+        id: LintId,
+        (level, src): LevelSource,
+    ) {
+        if let Some((old_level, old_src)) = specs.get(&id) {
+            if old_level == &Level::Forbid && level != Level::Forbid {
+                let mut diag_builder = struct_span_err!(
+                    self.sess,
+                    src.span(),
+                    E0453,
+                    "{}({}) incompatible with previous forbid in same scope",
+                    level.as_str(),
+                    src.name(),
+                );
+                match *old_src {
+                    LintSource::Default => {}
+                    LintSource::Node(_, forbid_source_span, reason) => {
+                        diag_builder.span_label(forbid_source_span, "`forbid` level set here");
+                        if let Some(rationale) = reason {
+                            diag_builder.note(&rationale.as_str());
+                        }
+                    }
+                    LintSource::CommandLine(_) => {
+                        diag_builder.note("`forbid` lint level was set on command line");
+                    }
+                }
+                diag_builder.emit();
+                return;
+            }
+        }
+        specs.insert(id, (level, src));
+    }
+
     /// Pushes a list of AST lint attributes onto this context.
     ///
     /// This function will return a `BuilderPush` object which should be passed
@@ -109,7 +148,7 @@
     ///   `#[allow]`
     ///
     /// Don't forget to call `pop`!
-    pub fn push(
+    pub(crate) fn push(
         &mut self,
         attrs: &[ast::Attribute],
         store: &LintStore,
@@ -221,7 +260,7 @@
                         let src = LintSource::Node(name, li.span(), reason);
                         for &id in ids {
                             self.check_gated_lint(id, attr.span);
-                            specs.insert(id, (level, src));
+                            self.insert_spec(&mut specs, id, (level, src));
                         }
                     }
 
@@ -235,7 +274,7 @@
                                     reason,
                                 );
                                 for id in ids {
-                                    specs.insert(*id, (level, src));
+                                    self.insert_spec(&mut specs, *id, (level, src));
                                 }
                             }
                             Err((Some(ids), new_lint_name)) => {
@@ -272,7 +311,7 @@
                                     reason,
                                 );
                                 for id in ids {
-                                    specs.insert(*id, (level, src));
+                                    self.insert_spec(&mut specs, *id, (level, src));
                                 }
                             }
                             Err((None, _)) => {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 33caedf..1db59bf 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -53,6 +53,7 @@
 mod nonstandard_style;
 mod passes;
 mod redundant_semicolon;
+mod traits;
 mod types;
 mod unused;
 
@@ -63,8 +64,8 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
     BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
-    EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, MISSING_DOC_CODE_EXAMPLES,
-    PRIVATE_DOC_TESTS,
+    EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS,
+    MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
 };
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
@@ -75,6 +76,7 @@
 use non_ascii_idents::*;
 use nonstandard_style::*;
 use redundant_semicolon::*;
+use traits::*;
 use types::*;
 use unused::*;
 
@@ -157,6 +159,7 @@
                 MissingDebugImplementations: MissingDebugImplementations::default(),
                 ArrayIntoIter: ArrayIntoIter,
                 ClashingExternDeclarations: ClashingExternDeclarations::new(),
+                DropTraitConstraints: DropTraitConstraints,
             ]
         );
     };
@@ -308,7 +311,8 @@
         PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
         MISSING_DOC_CODE_EXAMPLES,
-        PRIVATE_DOC_TESTS
+        PRIVATE_DOC_TESTS,
+        INVALID_HTML_TAGS
     );
 
     // Register renamed and removed lints.
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 159286c..828f283 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -33,6 +33,7 @@
             fn check_expr(a: &$hir hir::Expr<$hir>);
             fn check_expr_post(a: &$hir hir::Expr<$hir>);
             fn check_ty(a: &$hir hir::Ty<$hir>);
+            fn check_generic_arg(a: &$hir hir::GenericArg<$hir>);
             fn check_generic_param(a: &$hir hir::GenericParam<$hir>);
             fn check_generics(a: &$hir hir::Generics<$hir>);
             fn check_where_predicate(a: &$hir hir::WherePredicate<$hir>);
@@ -176,6 +177,7 @@
             fn check_expr(a: &ast::Expr);
             fn check_expr_post(a: &ast::Expr);
             fn check_ty(a: &ast::Ty);
+            fn check_generic_arg(a: &ast::GenericArg);
             fn check_generic_param(a: &ast::GenericParam);
             fn check_generics(a: &ast::Generics);
             fn check_where_predicate(a: &ast::WherePredicate);
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
new file mode 100644
index 0000000..d4f7903
--- /dev/null
+++ b/compiler/rustc_lint/src/traits.rs
@@ -0,0 +1,79 @@
+use crate::LateContext;
+use crate::LateLintPass;
+use crate::LintContext;
+use rustc_hir as hir;
+use rustc_span::symbol::sym;
+
+declare_lint! {
+    /// The `drop_bounds` lint checks for generics with `std::ops::Drop` as
+    /// bounds.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo<T: Drop>() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `Drop` bounds do not really accomplish anything. A type may have
+    /// compiler-generated drop glue without implementing the `Drop` trait
+    /// itself. The `Drop` trait also only has one method, `Drop::drop`, and
+    /// that function is by fiat not callable in user code. So there is really
+    /// no use case for using `Drop` in trait bounds.
+    ///
+    /// The most likely use case of a drop bound is to distinguish between
+    /// types that have destructors and types that don't. Combined with
+    /// specialization, a naive coder would write an implementation that
+    /// assumed a type could be trivially dropped, then write a specialization
+    /// for `T: Drop` that actually calls the destructor. Except that doing so
+    /// is not correct; String, for example, doesn't actually implement Drop,
+    /// but because String contains a Vec, assuming it can be trivially dropped
+    /// will leak memory.
+    pub DROP_BOUNDS,
+    Warn,
+    "bounds of the form `T: Drop` are useless"
+}
+
+declare_lint_pass!(
+    /// Lint for bounds of the form `T: Drop`, which usually
+    /// indicate an attempt to emulate `std::mem::needs_drop`.
+    DropTraitConstraints => [DROP_BOUNDS]
+);
+
+impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+        use rustc_middle::ty::PredicateAtom::*;
+
+        let def_id = cx.tcx.hir().local_def_id(item.hir_id);
+        let predicates = cx.tcx.explicit_predicates_of(def_id);
+        for &(predicate, span) in predicates.predicates {
+            let trait_predicate = match predicate.skip_binders() {
+                Trait(trait_predicate, _constness) => trait_predicate,
+                _ => continue,
+            };
+            let def_id = trait_predicate.trait_ref.def_id;
+            if cx.tcx.lang_items().drop_trait() == Some(def_id) {
+                // Explicitly allow `impl Drop`, a drop-guards-as-Voldemort-type pattern.
+                if trait_predicate.trait_ref.self_ty().is_impl_trait() {
+                    continue;
+                }
+                cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
+                    let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
+                        Some(needs_drop) => needs_drop,
+                        None => return,
+                    };
+                    let msg = format!(
+                        "bounds on `{}` are useless, consider instead \
+                         using `{}` to detect if a type has a destructor",
+                        predicate,
+                        cx.tcx.def_path_str(needs_drop)
+                    );
+                    lint.build(&msg).emit()
+                });
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 9925444..b502bd7 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -145,9 +145,9 @@
                     // We need to preserve the literal's suffix,
                     // as it may determine typing information.
                     let suffix = match lit.node {
-                        LitKind::Int(_, LitIntType::Signed(s)) => s.name_str().to_string(),
-                        LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str().to_string(),
-                        LitKind::Int(_, LitIntType::Unsuffixed) => "".to_string(),
+                        LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(),
+                        LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(),
+                        LitKind::Int(_, LitIntType::Unsuffixed) => "",
                         _ => bug!(),
                     };
                     let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
@@ -170,24 +170,25 @@
 // warnings are consistent between 32- and 64-bit platforms.
 fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) {
     match int_ty {
-        ast::IntTy::Isize => (i64::MIN as i128, i64::MAX as i128),
-        ast::IntTy::I8 => (i8::MIN as i64 as i128, i8::MAX as i128),
-        ast::IntTy::I16 => (i16::MIN as i64 as i128, i16::MAX as i128),
-        ast::IntTy::I32 => (i32::MIN as i64 as i128, i32::MAX as i128),
-        ast::IntTy::I64 => (i64::MIN as i128, i64::MAX as i128),
-        ast::IntTy::I128 => (i128::MIN as i128, i128::MAX),
+        ast::IntTy::Isize => (i64::MIN.into(), i64::MAX.into()),
+        ast::IntTy::I8 => (i8::MIN.into(), i8::MAX.into()),
+        ast::IntTy::I16 => (i16::MIN.into(), i16::MAX.into()),
+        ast::IntTy::I32 => (i32::MIN.into(), i32::MAX.into()),
+        ast::IntTy::I64 => (i64::MIN.into(), i64::MAX.into()),
+        ast::IntTy::I128 => (i128::MIN, i128::MAX),
     }
 }
 
 fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) {
-    match uint_ty {
-        ast::UintTy::Usize => (u64::MIN as u128, u64::MAX as u128),
-        ast::UintTy::U8 => (u8::MIN as u128, u8::MAX as u128),
-        ast::UintTy::U16 => (u16::MIN as u128, u16::MAX as u128),
-        ast::UintTy::U32 => (u32::MIN as u128, u32::MAX as u128),
-        ast::UintTy::U64 => (u64::MIN as u128, u64::MAX as u128),
-        ast::UintTy::U128 => (u128::MIN, u128::MAX),
-    }
+    let max = match uint_ty {
+        ast::UintTy::Usize => u64::MAX.into(),
+        ast::UintTy::U8 => u8::MAX.into(),
+        ast::UintTy::U16 => u16::MAX.into(),
+        ast::UintTy::U32 => u32::MAX.into(),
+        ast::UintTy::U64 => u64::MAX.into(),
+        ast::UintTy::U128 => u128::MAX,
+    };
+    (0, max)
 }
 
 fn get_bin_hex_repr(cx: &LateContext<'_>, lit: &hir::Lit) -> Option<String> {
@@ -304,7 +305,7 @@
     t: ast::IntTy,
     v: u128,
 ) {
-    let int_type = t.normalize(cx.sess().target.ptr_width);
+    let int_type = t.normalize(cx.sess().target.pointer_width);
     let (min, max) = int_ty_range(int_type);
     let max = max as u128;
     let negative = type_limits.negated_expr_id == Some(e.hir_id);
@@ -352,7 +353,7 @@
     lit: &hir::Lit,
     t: ast::UintTy,
 ) {
-    let uint_type = t.normalize(cx.sess().target.ptr_width);
+    let uint_type = t.normalize(cx.sess().target.pointer_width);
     let (min, max) = uint_ty_range(uint_type);
     let lit_val: u128 = match lit.node {
         // _v is u8, within range by definition
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 1e8c300..2409069 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -200,7 +200,7 @@
                 ty::Adt(def, _) => check_must_use_def(cx, def.did, span, descr_pre, descr_post),
                 ty::Opaque(def, _) => {
                     let mut has_emitted = false;
-                    for (predicate, _) in cx.tcx.predicates_of(def).predicates {
+                    for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
                         // We only look at the `DefId`, so it is safe to skip the binder here.
                         if let ty::PredicateAtom::Trait(ref poly_trait_predicate, _) =
                             predicate.skip_binders()
@@ -751,13 +751,20 @@
                 if !Self::is_expr_delims_necessary(inner, followed_by_block)
                     && value.attrs.is_empty()
                     && !value.span.from_expansion()
+                    && (ctx != UnusedDelimsCtx::LetScrutineeExpr
+                        || match inner.kind {
+                            ast::ExprKind::Binary(
+                                rustc_span::source_map::Spanned { node, .. },
+                                _,
+                                _,
+                            ) if node.lazy() => false,
+                            _ => true,
+                        })
                 {
                     self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
                 }
             }
             ast::ExprKind::Let(_, ref expr) => {
-                // FIXME(#60336): Properly handle `let true = (false && true)`
-                // actually needing the parenthesis.
                 self.check_unused_delims_expr(
                     cx,
                     expr,
@@ -839,10 +846,6 @@
         }
     }
 
-    fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) {
-        self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None);
-    }
-
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
         if let StmtKind::Local(ref local) = s.kind {
             self.check_unused_parens_pat(cx, &local.pat, false, false);
@@ -965,13 +968,6 @@
                         if !Self::is_expr_delims_necessary(expr, followed_by_block)
                             && (ctx != UnusedDelimsCtx::AnonConst
                                 || matches!(expr.kind, ast::ExprKind::Lit(_)))
-                            // array length expressions are checked during `check_anon_const` and `check_ty`,
-                            // once as `ArrayLenExpr` and once as `AnonConst`.
-                            //
-                            // As we do not want to lint this twice, we do not emit an error for
-                            // `ArrayLenExpr` if `AnonConst` would do the same.
-                            && (ctx != UnusedDelimsCtx::ArrayLenExpr
-                                || !matches!(expr.kind, ast::ExprKind::Lit(_)))
                             && !cx.sess().source_map().is_multiline(value.span)
                             && value.attrs.is_empty()
                             && !value.span.from_expansion()
@@ -999,21 +995,54 @@
 }
 
 impl EarlyLintPass for UnusedBraces {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        <Self as UnusedDelimLint>::check_expr(self, cx, e)
-    }
-
-    fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) {
-        self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None);
-    }
-
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
         <Self as UnusedDelimLint>::check_stmt(self, cx, s)
     }
 
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
+        <Self as UnusedDelimLint>::check_expr(self, cx, e);
+
+        if let ExprKind::Repeat(_, ref anon_const) = e.kind {
+            self.check_unused_delims_expr(
+                cx,
+                &anon_const.value,
+                UnusedDelimsCtx::AnonConst,
+                false,
+                None,
+                None,
+            );
+        }
+    }
+
+    fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
+        if let ast::GenericArg::Const(ct) = arg {
+            self.check_unused_delims_expr(
+                cx,
+                &ct.value,
+                UnusedDelimsCtx::AnonConst,
+                false,
+                None,
+                None,
+            );
+        }
+    }
+
+    fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) {
+        if let Some(anon_const) = &v.disr_expr {
+            self.check_unused_delims_expr(
+                cx,
+                &anon_const.value,
+                UnusedDelimsCtx::AnonConst,
+                false,
+                None,
+                None,
+            );
+        }
+    }
+
     fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
-        if let &ast::TyKind::Paren(ref r) = &ty.kind {
-            if let ast::TyKind::Array(_, ref len) = r.kind {
+        match ty.kind {
+            ast::TyKind::Array(_, ref len) => {
                 self.check_unused_delims_expr(
                     cx,
                     &len.value,
@@ -1023,6 +1052,19 @@
                     None,
                 );
             }
+
+            ast::TyKind::Typeof(ref anon_const) => {
+                self.check_unused_delims_expr(
+                    cx,
+                    &anon_const.value,
+                    UnusedDelimsCtx::AnonConst,
+                    false,
+                    None,
+                    None,
+                );
+            }
+
+            _ => {}
         }
     }
 
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 7f1e5cf..54b22ca 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -70,7 +70,7 @@
     let host = env::var("HOST").expect("HOST was not set");
     let is_crossed = target != host;
 
-    let mut optional_components = vec![
+    let optional_components = &[
         "x86",
         "arm",
         "aarch64",
@@ -85,6 +85,7 @@
         "sparc",
         "nvptx",
         "hexagon",
+        "riscv",
     ];
 
     let mut version_cmd = Command::new(&llvm_config);
@@ -94,13 +95,9 @@
     let (major, _minor) = if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
         (major, minor)
     } else {
-        (6, 0)
+        (8, 0)
     };
 
-    if major > 6 {
-        optional_components.push("riscv");
-    }
-
     let required_components = &[
         "ipo",
         "bitreader",
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 7b1c3f9..71ca4f2 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1212,6 +1212,7 @@
   StringMap<FunctionImporter::ImportMapTy> ImportLists;
   StringMap<FunctionImporter::ExportSetTy> ExportLists;
   StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
+  StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
 
   LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {}
 };
@@ -1308,7 +1309,6 @@
   //
   // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` with some of this
   // being lifted from `lib/LTO/LTO.cpp` as well
-  StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
   DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
   for (auto &I : Ret->Index) {
     if (I.second.SummaryList.size() > 1)
@@ -1323,7 +1323,7 @@
   auto recordNewLinkage = [&](StringRef ModuleIdentifier,
                               GlobalValue::GUID GUID,
                               GlobalValue::LinkageTypes NewLinkage) {
-    ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
+    Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
   };
 #if LLVM_VERSION_GE(9, 0)
   thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage,
@@ -1491,7 +1491,7 @@
 // Calls `module_name_callback` for each module import done by ThinLTO.
 // The callback is provided with regular null-terminated C strings.
 extern "C" void
-LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *data,
+LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data,
                                 LLVMRustModuleNameCallback module_name_callback,
                                 void* callback_payload) {
   for (const auto& importing_module : data->ImportLists) {
@@ -1653,3 +1653,36 @@
   MD->clearOperands();
   MD->addOperand(Unit);
 }
+
+// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
+// storing the result in 'KeyOut'.
+// Currently, this cache key is a SHA-1 hash of anything that could affect
+// the result of optimizing this module (e.g. module imports, exports, liveness
+// of access globals, etc).
+// The precise details are determined by LLVM in `computeLTOCacheKey`, which is
+// used during the normal linker-plugin incremental thin-LTO process.
+extern "C" void
+LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThinLTOData *Data) {
+  SmallString<40> Key;
+  llvm::lto::Config conf;
+  const auto &ImportList = Data->ImportLists.lookup(ModId);
+  const auto &ExportList = Data->ExportLists.lookup(ModId);
+  const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
+  const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
+  std::set<GlobalValue::GUID> CfiFunctionDefs;
+  std::set<GlobalValue::GUID> CfiFunctionDecls;
+
+  // Based on the 'InProcessThinBackend' constructor in LLVM
+  for (auto &Name : Data->Index.cfiFunctionDefs())
+    CfiFunctionDefs.insert(
+        GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
+  for (auto &Name : Data->Index.cfiFunctionDecls())
+    CfiFunctionDecls.insert(
+        GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
+
+  llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId,
+      ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls
+  );
+
+  LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size());
+}
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index e85a9b7..9f8ea7f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1171,6 +1171,7 @@
   OptimizationFailure,
   PGOProfile,
   Linker,
+  Unsupported,
 };
 
 static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
@@ -1197,6 +1198,8 @@
     return LLVMRustDiagnosticKind::PGOProfile;
   case DK_Linker:
     return LLVMRustDiagnosticKind::Linker;
+  case DK_Unsupported:
+    return LLVMRustDiagnosticKind::Unsupported;
   default:
     return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
                ? LLVMRustDiagnosticKind::OptimizationRemarkOther
diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs
index 4bf4ce0..ad7ac74 100644
--- a/compiler/rustc_macros/src/lift.rs
+++ b/compiler/rustc_macros/src/lift.rs
@@ -3,6 +3,7 @@
 
 pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     s.add_bounds(synstructure::AddBounds::Generics);
+    s.bind_with(|_| synstructure::BindStyle::Move);
 
     let tcx: syn::Lifetime = parse_quote!('tcx);
     let newtcx: syn::GenericParam = parse_quote!('__lifted);
@@ -43,8 +44,8 @@
         quote! {
             type Lifted = #lifted;
 
-            fn lift_to_tcx(&self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> {
-                Some(match *self { #body })
+            fn lift_to_tcx(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> {
+                Some(match self { #body })
             }
         },
     )
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index f7454da..44f57cf 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -127,7 +127,7 @@
         if ty == CrateType::Staticlib
             || (ty == CrateType::Executable
                 && sess.crt_static(Some(ty))
-                && !sess.target.target.options.crt_static_allows_dylibs)
+                && !sess.target.options.crt_static_allows_dylibs)
         {
             for &cnum in tcx.crates().iter() {
                 if tcx.dep_kind(cnum).macros_only() {
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 0869ec2..f225f8a 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -325,7 +325,7 @@
             hash,
             host_hash,
             extra_filename,
-            target: if is_host { &sess.host } else { &sess.target.target },
+            target: if is_host { &sess.host } else { &sess.target },
             triple: if is_host {
                 TargetTriple::from_triple(config::host_triple())
             } else {
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index e76c2cb..5e65f07 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -149,7 +149,7 @@
             }
             return;
         }
-        let is_osx = self.tcx.sess.target.target.options.is_like_osx;
+        let is_osx = self.tcx.sess.target.options.is_like_osx;
         if lib.kind == NativeLibKind::Framework && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index c31e941..b01a55b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -313,27 +313,6 @@
         Ok(ty)
     }
 
-    fn cached_predicate_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
-    {
-        let tcx = self.tcx();
-
-        let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
-
-        if let Some(&pred) = tcx.pred_rcache.borrow().get(&key) {
-            return Ok(pred);
-        }
-
-        let pred = or_insert_with(self)?;
-        tcx.pred_rcache.borrow_mut().insert(key, pred);
-        Ok(pred)
-    }
-
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
@@ -937,7 +916,7 @@
             .tables
             .inferred_outlives
             .get(self, item_id)
-            .map(|predicates| predicates.decode((self, tcx)))
+            .map(|predicates| tcx.arena.alloc_from_iter(predicates.decode((self, tcx))))
             .unwrap_or_default()
     }
 
@@ -949,6 +928,19 @@
         self.root.tables.super_predicates.get(self, item_id).unwrap().decode((self, tcx))
     }
 
+    fn get_explicit_item_bounds(
+        &self,
+        item_id: DefIndex,
+        tcx: TyCtxt<'tcx>,
+    ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+        self.root
+            .tables
+            .explicit_item_bounds
+            .get(self, item_id)
+            .map(|bounds| tcx.arena.alloc_from_iter(bounds.decode((self, tcx))))
+            .unwrap_or_default()
+    }
+
     fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
         self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
     }
@@ -1011,6 +1003,10 @@
         self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx)))
     }
 
+    fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId {
+        self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess))
+    }
+
     /// Iterates over all the stability attributes in the given crate.
     fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
         // FIXME: For a proc macro crate, not sure whether we should return the "host"
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 4102cf8..05b8dad 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -89,11 +89,12 @@
     explicit_predicates_of => { cdata.get_explicit_predicates(def_id.index, tcx) }
     inferred_outlives_of => { cdata.get_inferred_outlives(def_id.index, tcx) }
     super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
+    explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
     trait_def => { cdata.get_trait_def(def_id.index, tcx.sess) }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
     adt_destructor => {
         let _ = cdata;
-        tcx.calculate_dtor(def_id, &mut |_,_| Ok(()))
+        tcx.calculate_dtor(def_id, |_,_| Ok(()))
     }
     variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
     associated_item_def_ids => {
@@ -238,6 +239,7 @@
     }
 
     crate_extern_paths => { cdata.source().paths().cloned().collect() }
+    expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 757156e..7e33a47 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -28,7 +28,6 @@
 use rustc_serialize::{opaque, Encodable, Encoder};
 use rustc_session::config::CrateType;
 use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext};
-use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
 use rustc_target::abi::VariantIdx;
@@ -436,8 +435,7 @@
 
     fn encode_info_for_items(&mut self) {
         let krate = self.tcx.hir().krate();
-        let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public };
-        self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs, &vis);
+        self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs);
 
         // Proc-macro crates only export proc-macro items, which are looked
         // up using `proc_macro_data`
@@ -739,14 +737,11 @@
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
-        let enum_id = tcx.hir().local_def_id_to_hir_id(def.did.expect_local());
-        let enum_vis = &tcx.hir().expect_item(enum_id).vis;
-
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        record!(self.tables.visibility[def_id] <-
-            ty::Visibility::from_hir(enum_vis, enum_id, self.tcx));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
@@ -784,17 +779,8 @@
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
-        // Variant constructors have the same visibility as the parent enums, unless marked as
-        // non-exhaustive, in which case they are lowered to `pub(crate)`.
-        let enum_id = tcx.hir().local_def_id_to_hir_id(def.did.expect_local());
-        let enum_vis = &tcx.hir().expect_item(enum_id).vis;
-        let mut ctor_vis = ty::Visibility::from_hir(enum_vis, enum_id, tcx);
-        if variant.is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public {
-            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-        }
-
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        record!(self.tables.visibility[def_id] <- ctor_vis);
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         self.encode_stability(def_id);
         self.encode_deprecation(def_id);
@@ -810,13 +796,7 @@
         self.encode_promoted_mir(def_id.expect_local());
     }
 
-    fn encode_info_for_mod(
-        &mut self,
-        id: hir::HirId,
-        md: &hir::Mod<'_>,
-        attrs: &[ast::Attribute],
-        vis: &hir::Visibility<'_>,
-    ) {
+    fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
         let tcx = self.tcx;
         let local_def_id = tcx.hir().local_def_id(id);
         let def_id = local_def_id.to_def_id();
@@ -849,7 +829,7 @@
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
-        record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id] <- attrs);
         if self.is_proc_macro {
@@ -880,9 +860,10 @@
         let variant_data = tcx.hir().expect_variant_data(variant_id);
 
         record!(self.tables.kind[def_id] <- EntryKind::Field);
-        record!(self.tables.visibility[def_id] <- field.vis);
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id] <- variant_data.fields()[field_index].attrs);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         self.encode_ident_span(def_id, field.ident);
         self.encode_stability(def_id);
         self.encode_deprecation(def_id);
@@ -904,26 +885,10 @@
             is_non_exhaustive: variant.is_field_list_non_exhaustive(),
         };
 
-        let struct_id = tcx.hir().local_def_id_to_hir_id(adt_def.did.expect_local());
-        let struct_vis = &tcx.hir().expect_item(struct_id).vis;
-        let mut ctor_vis = ty::Visibility::from_hir(struct_vis, struct_id, tcx);
-        for field in &variant.fields {
-            if ctor_vis.is_at_least(field.vis, tcx) {
-                ctor_vis = field.vis;
-            }
-        }
-
-        // If the structure is marked as non_exhaustive then lower the visibility
-        // to within the crate.
-        if adt_def.non_enum_variant().is_field_list_non_exhaustive()
-            && ctor_vis == ty::Visibility::Public
-        {
-            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-        }
-
         record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
-        record!(self.tables.visibility[def_id] <- ctor_vis);
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         self.encode_stability(def_id);
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
@@ -962,6 +927,14 @@
         record!(self.tables.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id));
     }
 
+    fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
+        let bounds = self.tcx.explicit_item_bounds(def_id);
+        if !bounds.is_empty() {
+            record!(self.tables.explicit_item_bounds[def_id] <- bounds);
+        }
+    }
+
     fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
         let tcx = self.tcx;
@@ -1014,9 +987,12 @@
                     has_self: trait_item.fn_has_self_parameter,
                 }))
             }
-            ty::AssocKind::Type => EntryKind::AssocType(container),
+            ty::AssocKind::Type => {
+                self.encode_explicit_item_bounds(def_id);
+                EntryKind::AssocType(container)
+            }
         });
-        record!(self.tables.visibility[def_id] <- trait_item.vis);
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- ast_item.span);
         record!(self.tables.attributes[def_id] <- ast_item.attrs);
         self.encode_ident_span(def_id, ast_item.ident);
@@ -1098,7 +1074,7 @@
             }
             ty::AssocKind::Type => EntryKind::AssocType(container)
         });
-        record!(self.tables.visibility[def_id] <- impl_item.vis);
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- ast_item.span);
         record!(self.tables.attributes[def_id] <- ast_item.attrs);
         self.encode_ident_span(def_id, impl_item.ident);
@@ -1247,12 +1223,15 @@
                 EntryKind::Fn(self.lazy(data))
             }
             hir::ItemKind::Mod(ref m) => {
-                return self.encode_info_for_mod(item.hir_id, m, &item.attrs, &item.vis);
+                return self.encode_info_for_mod(item.hir_id, m, &item.attrs);
             }
             hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod,
             hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
             hir::ItemKind::TyAlias(..) => EntryKind::Type,
-            hir::ItemKind::OpaqueTy(..) => EntryKind::OpaqueTy,
+            hir::ItemKind::OpaqueTy(..) => {
+                self.encode_explicit_item_bounds(def_id);
+                EntryKind::OpaqueTy
+            }
             hir::ItemKind::Enum(..) => EntryKind::Enum(self.tcx.adt_def(def_id).repr),
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
@@ -1335,10 +1314,10 @@
             hir::ItemKind::ExternCrate(_) |
             hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item),
         });
-        record!(self.tables.visibility[def_id] <-
-            ty::Visibility::from_hir(&item.vis, item.hir_id, tcx));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id] <- item.attrs);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
             hir::ItemKind::ForeignMod(ref fm) => record!(self.tables.children[def_id] <-
@@ -1452,7 +1431,7 @@
     fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) {
         let def_id = self.tcx.hir().local_def_id(macro_def.hir_id).to_def_id();
         record!(self.tables.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone())));
-        record!(self.tables.visibility[def_id] <- ty::Visibility::Public);
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- macro_def.span);
         record!(self.tables.attributes[def_id] <- macro_def.attrs);
         self.encode_ident_span(def_id, macro_def.ident);
@@ -1462,7 +1441,6 @@
 
     fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) {
         record!(self.tables.kind[def_id] <- kind);
-        record!(self.tables.visibility[def_id] <- ty::Visibility::Public);
         record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         if encode_type {
             self.encode_item_type(def_id);
@@ -1487,7 +1465,6 @@
 
             _ => bug!("closure that is neither generator nor closure"),
         });
-        record!(self.tables.visibility[def_id.to_def_id()] <- ty::Visibility::Public);
         record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
         record!(self.tables.attributes[def_id.to_def_id()] <- &self.tcx.get_attrs(def_id.to_def_id())[..]);
         self.encode_item_type(def_id.to_def_id());
@@ -1507,7 +1484,6 @@
         let qualifs = self.tcx.mir_const_qualif(def_id);
 
         record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data));
-        record!(self.tables.visibility[def_id.to_def_id()] <- ty::Visibility::Public);
         record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
         self.encode_item_type(def_id.to_def_id());
         self.encode_generics(def_id.to_def_id());
@@ -1744,8 +1720,7 @@
             hir::ForeignItemKind::Static(_, hir::Mutability::Not) => EntryKind::ForeignImmStatic,
             hir::ForeignItemKind::Type => EntryKind::ForeignType,
         });
-        record!(self.tables.visibility[def_id] <-
-            ty::Visibility::from_hir(&nitem.vis, nitem.hir_id, self.tcx));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
         record!(self.tables.span[def_id] <- nitem.span);
         record!(self.tables.attributes[def_id] <- nitem.attrs);
         self.encode_ident_span(def_id, nitem.ident);
@@ -1753,6 +1728,7 @@
         self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
+        self.encode_inherent_implementations(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
             self.encode_variances_of(def_id);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 1a12703..2bd2019 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -294,13 +294,12 @@
     variances: Table<DefIndex, Lazy<[ty::Variance]>>,
     generics: Table<DefIndex, Lazy<ty::Generics>>,
     explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
-    // FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate`
-    // doesn't handle shorthands in its own (de)serialization impls,
-    // as it's an `enum` for which we want to derive (de)serialization,
-    // so the `ty::codec` APIs handle the whole `&'tcx [...]` at once.
-    // Also, as an optimization, a missing entry indicates an empty `&[]`.
-    inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
+    expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
+    // As an optimization, a missing entry indicates an empty `&[]`.
+    inferred_outlives: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
     super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
+    // As an optimization, a missing entry indicates an empty `&[]`.
+    explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
     mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
     mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index e8ace36..bdbc9ab 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -26,7 +26,7 @@
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.29.0"
+chalk-ir = "0.32.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 measureme = "0.7.1"
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index ceb873a..57f03c2 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -535,15 +535,15 @@
             Some(Node::Binding(_)) => (),
             _ => return false,
         }
-        match self.find(self.get_parent_node(id)) {
+        matches!(
+            self.find(self.get_parent_node(id)),
             Some(
                 Node::Item(_)
                 | Node::TraitItem(_)
                 | Node::ImplItem(_)
                 | Node::Expr(Expr { kind: ExprKind::Closure(..), .. }),
-            ) => true,
-            _ => false,
-        }
+            )
+        )
     }
 
     /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
@@ -554,10 +554,10 @@
 
     /// Whether `hir_id` corresponds to a `mod` or a crate.
     pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
-        match self.get_entry(hir_id).node {
-            Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..) => true,
-            _ => false,
-        }
+        matches!(
+            self.get_entry(hir_id).node,
+            Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
+        )
     }
 
     /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index bcb56fa..5da4be4 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -103,7 +103,7 @@
 
     /// Returns the type of this `Place` after all projections have been applied.
     pub fn ty(&self) -> Ty<'tcx> {
-        self.projections.last().map_or_else(|| self.base_ty, |proj| proj.ty)
+        self.projections.last().map_or(self.base_ty, |proj| proj.ty)
     }
 
     /// Returns the type of this `Place` immediately before `projection_index`th projection
diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs
index c2d177b..d6c6cef 100644
--- a/compiler/rustc_middle/src/ich/impls_hir.rs
+++ b/compiler/rustc_middle/src/ich/impls_hir.rs
@@ -221,6 +221,12 @@
     }
 }
 
+impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InstructionSetAttr {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+    }
+}
+
 impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
         mem::discriminant(self).hash_stable(hcx, hasher);
diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs
index e3d4655..7aba4fc 100644
--- a/compiler/rustc_middle/src/ich/impls_syntax.rs
+++ b/compiler/rustc_middle/src/ich/impls_syntax.rs
@@ -5,7 +5,7 @@
 
 use rustc_ast as ast;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_span::SourceFile;
+use rustc_span::{BytePos, NormalizedPos, SourceFile};
 
 use smallvec::SmallVec;
 
@@ -102,22 +102,19 @@
     }
 }
 
-fn stable_byte_pos(pos: ::rustc_span::BytePos, source_file_start: ::rustc_span::BytePos) -> u32 {
+fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 {
     pos.0 - source_file_start.0
 }
 
-fn stable_multibyte_char(
-    mbc: ::rustc_span::MultiByteChar,
-    source_file_start: ::rustc_span::BytePos,
-) -> (u32, u32) {
-    let ::rustc_span::MultiByteChar { pos, bytes } = mbc;
+fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) {
+    let rustc_span::MultiByteChar { pos, bytes } = mbc;
 
     (pos.0 - source_file_start.0, bytes as u32)
 }
 
 fn stable_non_narrow_char(
-    swc: ::rustc_span::NonNarrowChar,
-    source_file_start: ::rustc_span::BytePos,
+    swc: rustc_span::NonNarrowChar,
+    source_file_start: BytePos,
 ) -> (u32, u32) {
     let pos = swc.pos();
     let width = swc.width();
@@ -125,11 +122,8 @@
     (pos.0 - source_file_start.0, width as u32)
 }
 
-fn stable_normalized_pos(
-    np: ::rustc_span::NormalizedPos,
-    source_file_start: ::rustc_span::BytePos,
-) -> (u32, u32) {
-    let ::rustc_span::NormalizedPos { pos, diff } = np;
+fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) {
+    let NormalizedPos { pos, diff } = np;
 
     (pos.0 - source_file_start.0, diff)
 }
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 25e5379..91e1d6e0 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -9,7 +9,7 @@
 use rustc_session::{DiagnosticMessageId, Session};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
-use rustc_span::{Span, Symbol};
+use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
 
 /// How a lint level was set.
 #[derive(Clone, Copy, PartialEq, Eq, HashStable)]
@@ -25,6 +25,24 @@
     CommandLine(Symbol),
 }
 
+impl LintSource {
+    pub fn name(&self) -> Symbol {
+        match *self {
+            LintSource::Default => symbol::kw::Default,
+            LintSource::Node(name, _, _) => name,
+            LintSource::CommandLine(name) => name,
+        }
+    }
+
+    pub fn span(&self) -> Span {
+        match *self {
+            LintSource::Default => DUMMY_SP,
+            LintSource::Node(_, span, _) => span,
+            LintSource::CommandLine(_) => DUMMY_SP,
+        }
+    }
+}
+
 pub type LevelSource = (Level, LintSource);
 
 pub struct LintLevelSets {
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index a5482b7..6ff0a94 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -29,8 +29,8 @@
         $(
             impl<$tcx> $crate::ty::Lift<$tcx> for $ty {
                 type Lifted = Self;
-                fn lift_to_tcx(&self, _: $crate::ty::TyCtxt<$tcx>) -> Option<Self> {
-                    Some(Clone::clone(self))
+                fn lift_to_tcx(self, _: $crate::ty::TyCtxt<$tcx>) -> Option<Self> {
+                    Some(self)
                 }
             }
         )+
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 62a6198..a4363bb 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,5 +1,5 @@
 use crate::mir::mono::Linkage;
-use rustc_attr::{InlineAttr, OptimizeAttr};
+use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_session::config::SanitizerSet;
 use rustc_span::symbol::Symbol;
 
@@ -34,6 +34,10 @@
     /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
     /// instrumentation should be disabled inside the annotated function.
     pub no_sanitize: SanitizerSet,
+    /// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
+    /// be generated against a specific instruction set. Only usable on architectures which allow
+    /// switching between multiple instruction sets.
+    pub instruction_set: Option<InstructionSetAttr>,
 }
 
 bitflags! {
@@ -79,6 +83,9 @@
         /// #[ffi_const]: applies clang's `const` attribute to a foreign function
         /// declaration.
         const FFI_CONST                 = 1 << 13;
+        /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a
+        /// function as an entry function from Non-Secure code.
+        const CMSE_NONSECURE_ENTRY      = 1 << 14;
     }
 }
 
@@ -95,6 +102,7 @@
             linkage: None,
             link_section: None,
             no_sanitize: SanitizerSet::empty(),
+            instruction_set: None,
         }
     }
 
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 4756e83..254b57a 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -3,7 +3,6 @@
 //! which are available for use externally when compiled as a library.
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::DefIdSet;
 use rustc_hir::HirId;
 use rustc_macros::HashStable;
 use std::fmt;
@@ -59,7 +58,3 @@
         fmt::Debug::fmt(&self.map, f)
     }
 }
-
-/// A set containing all exported definitions from external crates.
-/// The set does not contain any entries from local crates.
-pub type ExternalExports = DefIdSet;
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 4c6ac82..d060549 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -283,25 +283,29 @@
     /// To see that this method works, consider:
     ///
     /// Let `D` be our binding/temporary and `U` be our other HIR node, with
-    /// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be
-    /// the yield and D would be one of the calls). Let's show that
-    /// `D` is storage-dead at `U`.
+    /// `HIR-postorder(U) < HIR-postorder(D)`. Suppose, as in our example,
+    /// U is the yield and D is one of the calls.
+    /// Let's show that `D` is storage-dead at `U`.
     ///
     /// Remember that storage-live/storage-dead refers to the state of
     /// the *storage*, and does not consider moves/drop flags.
     ///
     /// Then:
-    ///     1. From the ordering guarantee of HIR visitors (see
-    ///     `rustc_hir::intravisit`), `D` does not dominate `U`.
-    ///     2. Therefore, `D` is *potentially* storage-dead at `U` (because
-    ///     we might visit `U` without ever getting to `D`).
-    ///     3. However, we guarantee that at each HIR point, each
-    ///     binding/temporary is always either always storage-live
-    ///     or always storage-dead. This is what is being guaranteed
-    ///     by `terminating_scopes` including all blocks where the
-    ///     count of executions is not guaranteed.
-    ///     4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`,
-    ///     QED.
+    ///
+    ///   1. From the ordering guarantee of HIR visitors (see
+    ///   `rustc_hir::intravisit`), `D` does not dominate `U`.
+    ///
+    ///   2. Therefore, `D` is *potentially* storage-dead at `U` (because
+    ///   we might visit `U` without ever getting to `D`).
+    ///
+    ///   3. However, we guarantee that at each HIR point, each
+    ///   binding/temporary is always either always storage-live
+    ///   or always storage-dead. This is what is being guaranteed
+    ///   by `terminating_scopes` including all blocks where the
+    ///   count of executions is not guaranteed.
+    ///
+    ///   4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`,
+    ///   QED.
     ///
     /// This property ought to not on (3) in an essential way -- it
     /// is probably still correct even if we have "unrestricted" terminating
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 7e2415f..1a206b2 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -256,24 +256,12 @@
 }
 
 // See issue #38412.
-fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, mut def_id: DefId) -> bool {
-    // Check if `def_id` is a trait method.
-    match tcx.def_kind(def_id) {
-        DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
-            if let ty::TraitContainer(trait_def_id) = tcx.associated_item(def_id).container {
-                // Trait methods do not declare visibility (even
-                // for visibility info in cstore). Use containing
-                // trait instead, so methods of `pub` traits are
-                // themselves considered `pub`.
-                def_id = trait_def_id;
-            }
-        }
-        _ => {}
+fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    if tcx.def_kind(def_id) == DefKind::TyParam {
+        // Have no visibility, considered public for the purpose of this check.
+        return false;
     }
-
-    let visibility = tcx.visibility(def_id);
-
-    match visibility {
+    match tcx.visibility(def_id) {
         // Must check stability for `pub` items.
         ty::Visibility::Public => false,
 
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
new file mode 100644
index 0000000..0421eab
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -0,0 +1,124 @@
+//! Metadata from source code coverage analysis and instrumentation.
+
+use rustc_macros::HashStable;
+use rustc_span::Symbol;
+
+use std::cmp::Ord;
+use std::fmt::{self, Debug, Formatter};
+
+rustc_index::newtype_index! {
+    pub struct ExpressionOperandId {
+        derive [HashStable]
+        DEBUG_FORMAT = "ExpressionOperandId({})",
+        MAX = 0xFFFF_FFFF,
+    }
+}
+
+impl ExpressionOperandId {
+    /// An expression operand for a "zero counter", as described in the following references:
+    ///
+    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter
+    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#tag
+    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter-expressions
+    ///
+    /// This operand can be used to count two or more separate code regions with a single counter,
+    /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
+    /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in
+    /// the coverage map for the other code regions.
+    pub const ZERO: Self = Self::from_u32(0);
+}
+
+rustc_index::newtype_index! {
+    pub struct CounterValueReference {
+        derive [HashStable]
+        DEBUG_FORMAT = "CounterValueReference({})",
+        MAX = 0xFFFF_FFFF,
+    }
+}
+
+impl CounterValueReference {
+    // Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
+    pub const START: Self = Self::from_u32(1);
+}
+
+rustc_index::newtype_index! {
+    pub struct InjectedExpressionIndex {
+        derive [HashStable]
+        DEBUG_FORMAT = "InjectedExpressionIndex({})",
+        MAX = 0xFFFF_FFFF,
+    }
+}
+
+rustc_index::newtype_index! {
+    pub struct MappedExpressionIndex {
+        derive [HashStable]
+        DEBUG_FORMAT = "MappedExpressionIndex({})",
+        MAX = 0xFFFF_FFFF,
+    }
+}
+
+impl From<CounterValueReference> for ExpressionOperandId {
+    #[inline]
+    fn from(v: CounterValueReference) -> ExpressionOperandId {
+        ExpressionOperandId::from(v.as_u32())
+    }
+}
+
+impl From<InjectedExpressionIndex> for ExpressionOperandId {
+    #[inline]
+    fn from(v: InjectedExpressionIndex) -> ExpressionOperandId {
+        ExpressionOperandId::from(v.as_u32())
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+pub enum CoverageKind {
+    Counter {
+        function_source_hash: u64,
+        id: CounterValueReference,
+    },
+    Expression {
+        id: InjectedExpressionIndex,
+        lhs: ExpressionOperandId,
+        op: Op,
+        rhs: ExpressionOperandId,
+    },
+    Unreachable,
+}
+
+impl CoverageKind {
+    pub fn as_operand_id(&self) -> ExpressionOperandId {
+        match *self {
+            CoverageKind::Counter { id, .. } => ExpressionOperandId::from(id),
+            CoverageKind::Expression { id, .. } => ExpressionOperandId::from(id),
+            CoverageKind::Unreachable => {
+                bug!("Unreachable coverage cannot be part of an expression")
+            }
+        }
+    }
+}
+
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, PartialEq, Eq, PartialOrd, Ord)]
+pub struct CodeRegion {
+    pub file_name: Symbol,
+    pub start_line: u32,
+    pub start_col: u32,
+    pub end_line: u32,
+    pub end_col: u32,
+}
+
+impl Debug for CodeRegion {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        write!(
+            fmt,
+            "{}:{}:{} - {}:{}",
+            self.file_name, self.start_line, self.start_col, self.end_line, self.end_col
+        )
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+pub enum Op {
+    Subtract,
+    Add,
+}
diff --git a/compiler/rustc_middle/src/mir/coverage/mod.rs b/compiler/rustc_middle/src/mir/coverage/mod.rs
deleted file mode 100644
index ce311c2..0000000
--- a/compiler/rustc_middle/src/mir/coverage/mod.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-//! Metadata from source code coverage analysis and instrumentation.
-
-use rustc_macros::HashStable;
-use rustc_span::Symbol;
-
-use std::cmp::Ord;
-use std::fmt::{self, Debug, Formatter};
-
-rustc_index::newtype_index! {
-    pub struct ExpressionOperandId {
-        derive [HashStable]
-        DEBUG_FORMAT = "ExpressionOperandId({})",
-        MAX = 0xFFFF_FFFF,
-    }
-}
-
-rustc_index::newtype_index! {
-    pub struct CounterValueReference {
-        derive [HashStable]
-        DEBUG_FORMAT = "CounterValueReference({})",
-        MAX = 0xFFFF_FFFF,
-    }
-}
-
-rustc_index::newtype_index! {
-    pub struct InjectedExpressionIndex {
-        derive [HashStable]
-        DEBUG_FORMAT = "InjectedExpressionIndex({})",
-        MAX = 0xFFFF_FFFF,
-    }
-}
-
-rustc_index::newtype_index! {
-    pub struct MappedExpressionIndex {
-        derive [HashStable]
-        DEBUG_FORMAT = "MappedExpressionIndex({})",
-        MAX = 0xFFFF_FFFF,
-    }
-}
-
-impl From<CounterValueReference> for ExpressionOperandId {
-    #[inline]
-    fn from(v: CounterValueReference) -> ExpressionOperandId {
-        ExpressionOperandId::from(v.as_u32())
-    }
-}
-
-impl From<InjectedExpressionIndex> for ExpressionOperandId {
-    #[inline]
-    fn from(v: InjectedExpressionIndex) -> ExpressionOperandId {
-        ExpressionOperandId::from(v.as_u32())
-    }
-}
-
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
-pub enum CoverageKind {
-    Counter {
-        function_source_hash: u64,
-        id: CounterValueReference,
-    },
-    Expression {
-        id: InjectedExpressionIndex,
-        lhs: ExpressionOperandId,
-        op: Op,
-        rhs: ExpressionOperandId,
-    },
-    Unreachable,
-}
-
-impl CoverageKind {
-    pub fn as_operand_id(&self) -> ExpressionOperandId {
-        match *self {
-            CoverageKind::Counter { id, .. } => ExpressionOperandId::from(id),
-            CoverageKind::Expression { id, .. } => ExpressionOperandId::from(id),
-            CoverageKind::Unreachable => {
-                bug!("Unreachable coverage cannot be part of an expression")
-            }
-        }
-    }
-}
-
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, PartialEq, Eq, PartialOrd, Ord)]
-pub struct CodeRegion {
-    pub file_name: Symbol,
-    pub start_line: u32,
-    pub start_col: u32,
-    pub end_line: u32,
-    pub end_col: u32,
-}
-
-impl Debug for CodeRegion {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        write!(
-            fmt,
-            "{}:{}:{} - {}:{}",
-            self.file_name, self.start_line, self.start_col, self.end_line, self.end_col
-        )
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
-pub enum Op {
-    Subtract,
-    Add,
-}
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index ee1ea81..5ebe38b 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -40,7 +40,7 @@
     pub extra: Extra,
 }
 
-pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone {
+pub trait AllocationExtra<Tag>: std::fmt::Debug + Clone {
     // There is no constructor in here because the constructor's type depends
     // on `MemoryKind`, and making things sufficiently generic leads to painful
     // inference failure.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 2036362..b5beb3b 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -486,10 +486,10 @@
         // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
         // However, formatting code relies on function identity (see #58320), so we only do
         // this for generic functions.  Lifetime parameters are ignored.
-        let is_generic = instance.substs.into_iter().any(|kind| match kind.unpack() {
-            GenericArgKind::Lifetime(_) => false,
-            _ => true,
-        });
+        let is_generic = instance
+            .substs
+            .into_iter()
+            .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
         if is_generic {
             // Get a fresh ID.
             let mut alloc_map = self.alloc_map.lock();
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 206f01c..cb8782c 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -56,15 +56,6 @@
         }
     }
 
-    pub fn try_to_str_slice(&self) -> Option<&'tcx str> {
-        if let ConstValue::Slice { data, start, end } = *self {
-            ::std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end))
-                .ok()
-        } else {
-            None
-        }
-    }
-
     pub fn try_to_bits(&self, size: Size) -> Option<u128> {
         self.try_to_scalar()?.to_bits(size).ok()
     }
@@ -445,19 +436,13 @@
     /// Do not call this method!  Dispatch based on the type instead.
     #[inline]
     pub fn is_bits(self) -> bool {
-        match self {
-            Scalar::Raw { .. } => true,
-            _ => false,
-        }
+        matches!(self, Scalar::Raw { .. })
     }
 
     /// Do not call this method!  Dispatch based on the type instead.
     #[inline]
     pub fn is_ptr(self) -> bool {
-        match self {
-            Scalar::Ptr(_) => true,
-            _ => false,
-        }
+        matches!(self, Scalar::Ptr(_))
     }
 
     pub fn to_bool(self) -> InterpResult<'tcx, bool> {
@@ -471,7 +456,7 @@
 
     pub fn to_char(self) -> InterpResult<'tcx, char> {
         let val = self.to_u32()?;
-        match ::std::char::from_u32(val) {
+        match std::char::from_u32(val) {
             Some(c) => Ok(c),
             None => throw_ub!(InvalidChar(val)),
         }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 8ff75bf..05bcf2b 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -3,19 +3,18 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
 use crate::mir::coverage::{CodeRegion, CoverageKind};
-use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
+use crate::mir::interpret::{Allocation, GlobalAlloc, Scalar};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{Subst, SubstsRef};
-use crate::ty::{
-    self, AdtDef, CanonicalUserTypeAnnotations, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex,
-};
+use crate::ty::{self, List, Ty, TyCtxt};
+use crate::ty::{AdtDef, InstanceDef, Region, UserTypeAnnotationIndex};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::{self, GeneratorKind};
 use rustc_target::abi::VariantIdx;
 
@@ -112,10 +111,42 @@
     }
 }
 
+/// Where a specific `mir::Body` comes from.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)]
+pub struct MirSource<'tcx> {
+    pub instance: InstanceDef<'tcx>,
+
+    /// If `Some`, this is a promoted rvalue within the parent function.
+    pub promoted: Option<Promoted>,
+}
+
+impl<'tcx> MirSource<'tcx> {
+    pub fn item(def_id: DefId) -> Self {
+        MirSource {
+            instance: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
+            promoted: None,
+        }
+    }
+
+    pub fn from_instance(instance: InstanceDef<'tcx>) -> Self {
+        MirSource { instance, promoted: None }
+    }
+
+    pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
+        self.instance.with_opt_param()
+    }
+
+    #[inline]
+    pub fn def_id(&self) -> DefId {
+        self.instance.def_id()
+    }
+}
+
 /// The lowered representation of a single function.
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)]
 pub struct Body<'tcx> {
-    /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock`
+    /// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`]
     /// that indexes into this vector.
     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
 
@@ -126,6 +157,8 @@
     /// us to see the difference and forego optimization on the inlined promoted items.
     pub phase: MirPhase,
 
+    pub source: MirSource<'tcx>,
+
     /// A list of source scopes; these are referenced by statements
     /// and used for debuginfo. Indexed by a `SourceScope`.
     pub source_scopes: IndexVec<SourceScope, SourceScopeData>,
@@ -151,7 +184,7 @@
     pub local_decls: LocalDecls<'tcx>,
 
     /// User type annotations.
-    pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
+    pub user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
 
     /// The number of arguments this function takes.
     ///
@@ -209,10 +242,11 @@
 
 impl<'tcx> Body<'tcx> {
     pub fn new(
+        source: MirSource<'tcx>,
         basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
         source_scopes: IndexVec<SourceScope, SourceScopeData>,
         local_decls: LocalDecls<'tcx>,
-        user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
+        user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
         arg_count: usize,
         var_debug_info: Vec<VarDebugInfo<'tcx>>,
         span: Span,
@@ -228,6 +262,7 @@
 
         let mut body = Body {
             phase: MirPhase::Build,
+            source,
             basic_blocks,
             source_scopes,
             yield_ty: None,
@@ -257,6 +292,7 @@
     pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
         let mut body = Body {
             phase: MirPhase::Build,
+            source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
             basic_blocks,
             source_scopes: IndexVec::new(),
             yield_ty: None,
@@ -424,17 +460,6 @@
         }
     }
 
-    /// Checks if `sub` is a sub scope of `sup`
-    pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool {
-        while sub != sup {
-            match self.source_scopes[sub].parent_scope {
-                None => return false,
-                Some(p) => sub = p,
-            }
-        }
-        true
-    }
-
     /// Returns the return type; it always return first element from `local_decls` array.
     #[inline]
     pub fn return_ty(&self) -> Ty<'tcx> {
@@ -670,7 +695,7 @@
 }
 
 /// Classifies locals into categories. See `Body::local_kind`.
-#[derive(PartialEq, Eq, Debug, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
 pub enum LocalKind {
     /// User-declared variable binding.
     Var,
@@ -739,7 +764,7 @@
     impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
         fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
             use super::BindingForm::*;
-            ::std::mem::discriminant(self).hash_stable(hcx, hasher);
+            std::mem::discriminant(self).hash_stable(hcx, hasher);
 
             match self {
                 Var(binding) => binding.hash_stable(hcx, hasher),
@@ -777,7 +802,7 @@
 /// argument, or the return place.
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct LocalDecl<'tcx> {
-    /// Whether this is a mutable minding (i.e., `let x` or `let mut x`).
+    /// Whether this is a mutable binding (i.e., `let x` or `let mut x`).
     ///
     /// Temporaries and the return place are always mutable.
     pub mutability: Mutability,
@@ -796,9 +821,6 @@
     /// flag drop flags to avoid triggering this check as they are introduced
     /// after typeck.
     ///
-    /// Unsafety checking will also ignore dereferences of these locals,
-    /// so they can be used for raw pointers only used in a desugaring.
-    ///
     /// This should be sound because the drop flags are fully algebraic, and
     /// therefore don't affect the OIBIT or outlives properties of the
     /// generator.
@@ -935,71 +957,63 @@
     /// - `let x = ...`,
     /// - or `match ... { C(x) => ... }`
     pub fn can_be_made_mutable(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                binding_mode: ty::BindingMode::BindByValue(_),
-                opt_ty_info: _,
-                opt_match_place: _,
-                pat_span: _,
-            })))) => true,
-
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
-                ImplicitSelfKind::Imm,
-            )))) => true,
-
-            _ => false,
-        }
+        matches!(
+            self.local_info,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(
+                BindingForm::Var(VarBindingForm {
+                    binding_mode: ty::BindingMode::BindByValue(_),
+                    opt_ty_info: _,
+                    opt_match_place: _,
+                    pat_span: _,
+                })
+                | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
+            )))
+        )
     }
 
     /// Returns `true` if local is definitely not a `ref ident` or
     /// `ref mut ident` binding. (Such bindings cannot be made into
     /// mutable bindings, but the inverse does not necessarily hold).
     pub fn is_nonref_binding(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
-                binding_mode: ty::BindingMode::BindByValue(_),
-                opt_ty_info: _,
-                opt_match_place: _,
-                pat_span: _,
-            })))) => true,
-
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(_)))) => true,
-
-            _ => false,
-        }
+        matches!(
+            self.local_info,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(
+                BindingForm::Var(VarBindingForm {
+                    binding_mode: ty::BindingMode::BindByValue(_),
+                    opt_ty_info: _,
+                    opt_match_place: _,
+                    pat_span: _,
+                })
+                | BindingForm::ImplicitSelf(_),
+            )))
+        )
     }
 
     /// Returns `true` if this variable is a named variable or function
     /// parameter declared by the user.
     #[inline]
     pub fn is_user_variable(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(_)) => true,
-            _ => false,
-        }
+        matches!(self.local_info, Some(box LocalInfo::User(_)))
     }
 
     /// Returns `true` if this is a reference to a variable bound in a `match`
     /// expression that is used to access said variable for the guard of the
     /// match arm.
     pub fn is_ref_for_guard(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) => true,
-            _ => false,
-        }
+        matches!(
+            self.local_info,
+            Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)))
+        )
     }
 
     /// Returns `Some` if this is a reference to a static item that is used to
-    /// access that static
+    /// access that static.
     pub fn is_ref_to_static(&self) -> bool {
-        match self.local_info {
-            Some(box LocalInfo::StaticRef { .. }) => true,
-            _ => false,
-        }
+        matches!(self.local_info, Some(box LocalInfo::StaticRef { .. }))
     }
 
-    /// Returns `Some` if this is a reference to a static item that is used to
-    /// access that static
+    /// Returns `Some` if this is a reference to a thread-local static item that is used to
+    /// access that static.
     pub fn is_ref_to_thread_local(&self) -> bool {
         match self.local_info {
             Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local,
@@ -1089,6 +1103,9 @@
     /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is
     /// needed because some analyses require that there are no critical edges in the CFG.
     ///
+    /// Note that this type is just an index into [`Body.basic_blocks`](Body::basic_blocks);
+    /// the actual data that a basic block holds is in [`BasicBlockData`].
+    ///
     /// Read more about basic blocks in the [rustc-dev-guide][guide-mir].
     ///
     /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
@@ -1300,49 +1317,49 @@
         match self {
             BoundsCheck { ref len, ref index } => write!(
                 f,
-                "\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}",
+                "\"index out of bounds: the length is {{}} but the index is {{}}\", {:?}, {:?}",
                 len, index
             ),
 
             OverflowNeg(op) => {
-                write!(f, "\"attempt to negate {{}} which would overflow\", {:?}", op)
+                write!(f, "\"attempt to negate `{{}}`, which would overflow\", {:?}", op)
             }
-            DivisionByZero(op) => write!(f, "\"attempt to divide {{}} by zero\", {:?}", op),
+            DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {:?}", op),
             RemainderByZero(op) => write!(
                 f,
-                "\"attempt to calculate the remainder of {{}} with a divisor of zero\", {:?}",
+                "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {:?}",
                 op
             ),
             Overflow(BinOp::Add, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} + {{}}` which would overflow\", {:?}, {:?}",
+                "\"attempt to compute `{{}} + {{}}`, which would overflow\", {:?}, {:?}",
                 l, r
             ),
             Overflow(BinOp::Sub, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} - {{}}` which would overflow\", {:?}, {:?}",
+                "\"attempt to compute `{{}} - {{}}`, which would overflow\", {:?}, {:?}",
                 l, r
             ),
             Overflow(BinOp::Mul, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} * {{}}` which would overflow\", {:?}, {:?}",
+                "\"attempt to compute `{{}} * {{}}`, which would overflow\", {:?}, {:?}",
                 l, r
             ),
             Overflow(BinOp::Div, l, r) => write!(
                 f,
-                "\"attempt to compute `{{}} / {{}}` which would overflow\", {:?}, {:?}",
+                "\"attempt to compute `{{}} / {{}}`, which would overflow\", {:?}, {:?}",
                 l, r
             ),
             Overflow(BinOp::Rem, l, r) => write!(
                 f,
-                "\"attempt to compute the remainder of `{{}} % {{}}` which would overflow\", {:?}, {:?}",
+                "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {:?}, {:?}",
                 l, r
             ),
             Overflow(BinOp::Shr, _, r) => {
-                write!(f, "\"attempt to shift right by {{}} which would overflow\", {:?}", r)
+                write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {:?}", r)
             }
             Overflow(BinOp::Shl, _, r) => {
-                write!(f, "\"attempt to shift left by {{}} which would overflow\", {:?}", r)
+                write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r)
             }
             _ => write!(f, "\"{}\"", self.description()),
         }
@@ -1353,36 +1370,40 @@
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use AssertKind::*;
         match self {
-            BoundsCheck { ref len, ref index } => {
-                write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index)
-            }
-            OverflowNeg(op) => write!(f, "attempt to negate {:#?} which would overflow", op),
-            DivisionByZero(op) => write!(f, "attempt to divide {:#?} by zero", op),
-            RemainderByZero(op) => {
-                write!(f, "attempt to calculate the remainder of {:#?} with a divisor of zero", op)
-            }
+            BoundsCheck { ref len, ref index } => write!(
+                f,
+                "index out of bounds: the length is {:?} but the index is {:?}",
+                len, index
+            ),
+            OverflowNeg(op) => write!(f, "attempt to negate `{:#?}`, which would overflow", op),
+            DivisionByZero(op) => write!(f, "attempt to divide `{:#?}` by zero", op),
+            RemainderByZero(op) => write!(
+                f,
+                "attempt to calculate the remainder of `{:#?}` with a divisor of zero",
+                op
+            ),
             Overflow(BinOp::Add, l, r) => {
-                write!(f, "attempt to compute `{:#?} + {:#?}` which would overflow", l, r)
+                write!(f, "attempt to compute `{:#?} + {:#?}`, which would overflow", l, r)
             }
             Overflow(BinOp::Sub, l, r) => {
-                write!(f, "attempt to compute `{:#?} - {:#?}` which would overflow", l, r)
+                write!(f, "attempt to compute `{:#?} - {:#?}`, which would overflow", l, r)
             }
             Overflow(BinOp::Mul, l, r) => {
-                write!(f, "attempt to compute `{:#?} * {:#?}` which would overflow", l, r)
+                write!(f, "attempt to compute `{:#?} * {:#?}`, which would overflow", l, r)
             }
             Overflow(BinOp::Div, l, r) => {
-                write!(f, "attempt to compute `{:#?} / {:#?}` which would overflow", l, r)
+                write!(f, "attempt to compute `{:#?} / {:#?}`, which would overflow", l, r)
             }
             Overflow(BinOp::Rem, l, r) => write!(
                 f,
-                "attempt to compute the remainder of `{:#?} % {:#?}` which would overflow",
+                "attempt to compute the remainder of `{:#?} % {:#?}`, which would overflow",
                 l, r
             ),
             Overflow(BinOp::Shr, _, r) => {
-                write!(f, "attempt to shift right by {:#?} which would overflow", r)
+                write!(f, "attempt to shift right by `{:#?}`, which would overflow", r)
             }
             Overflow(BinOp::Shl, _, r) => {
-                write!(f, "attempt to shift left by {:#?} which would overflow", r)
+                write!(f, "attempt to shift left by `{:#?}`, which would overflow", r)
             }
             _ => write!(f, "{}", self.description()),
         }
@@ -1946,45 +1967,6 @@
         })
     }
 
-    /// Convenience helper to make a `Scalar` from the given `Operand`, assuming that `Operand`
-    /// wraps a constant literal value. Panics if this is not the case.
-    pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar {
-        match operand {
-            Operand::Constant(constant) => match constant.literal.val.try_to_scalar() {
-                Some(scalar) => scalar,
-                _ => panic!("{:?}: Scalar value expected", constant.literal.val),
-            },
-            _ => panic!("{:?}: Constant expected", operand),
-        }
-    }
-
-    /// Convenience helper to make a literal-like constant from a given `&str` slice.
-    /// Since this is used to synthesize MIR, assumes `user_ty` is None.
-    pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> {
-        let tcx = tcx;
-        let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes());
-        let allocation = tcx.intern_const_alloc(allocation);
-        let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() };
-        let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_);
-        Operand::Constant(box Constant {
-            span,
-            user_ty: None,
-            literal: ty::Const::from_value(tcx, const_val, ty),
-        })
-    }
-
-    /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand`
-    /// wraps a constant value (such as a `&str` slice). Panics if this is not the case.
-    pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> {
-        match operand {
-            Operand::Constant(constant) => match constant.literal.val.try_to_value() {
-                Some(const_value) => const_value,
-                _ => panic!("{:?}: ConstValue expected", constant.literal.val),
-            },
-            _ => panic!("{:?}: Constant expected", operand),
-        }
-    }
-
     pub fn to_copy(&self) -> Self {
         match *self {
             Operand::Copy(_) | Operand::Constant(_) => self.clone(),
@@ -2124,10 +2106,7 @@
 impl BinOp {
     pub fn is_checkable(self) -> bool {
         use self::BinOp::*;
-        match self {
-            Add | Sub | Mul | Shl | Shr => true,
-            _ => false,
-        }
+        matches!(self, Add | Sub | Mul | Shl | Shr)
     }
 }
 
@@ -2231,7 +2210,7 @@
 
                         let name = ty::tls::with(|tcx| {
                             let mut name = String::new();
-                            let substs = tcx.lift(&substs).expect("could not lift for printing");
+                            let substs = tcx.lift(substs).expect("could not lift for printing");
                             FmtPrinter::new(tcx, &mut name, Namespace::ValueNS)
                                 .print_def_path(variant_def.def_id, substs)?;
                             Ok(name)
@@ -2254,7 +2233,7 @@
                         if let Some(def_id) = def_id.as_local() {
                             let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
                             let name = if tcx.sess.opts.debugging_opts.span_free_formats {
-                                let substs = tcx.lift(&substs).unwrap();
+                                let substs = tcx.lift(substs).unwrap();
                                 format!(
                                     "[closure@{}]",
                                     tcx.def_path_str_with_substs(def_id.to_def_id(), substs),
@@ -2384,10 +2363,6 @@
         self.contents.is_empty()
     }
 
-    pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self {
-        UserTypeProjections { contents: projs.collect() }
-    }
-
     pub fn projections_and_spans(
         &self,
     ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator {
@@ -2552,7 +2527,7 @@
 ) -> fmt::Result {
     use crate::ty::print::PrettyPrinter;
     ty::tls::with(|tcx| {
-        let literal = tcx.lift(&c).unwrap();
+        let literal = tcx.lift(c).unwrap();
         let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS);
         cx.print_alloc_ids = true;
         cx.pretty_print_const(literal, print_types)?;
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 0878e93..6022194 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,9 +1,10 @@
 //! Values computed by queries that use MIR.
 
-use crate::mir::{Body, Promoted};
+use crate::mir::{abstract_const, Body, Promoted};
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::bit_set::BitMatrix;
@@ -407,18 +408,12 @@
     pub num_expressions: u32,
 }
 
+/// Shims which make dealing with `WithOptConstParam` easier.
+///
+/// For more information on why this is needed, consider looking
+/// at the docs for `WithOptConstParam` itself.
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn mir_borrowck_opt_const_arg(
-        self,
-        def: ty::WithOptConstParam<LocalDefId>,
-    ) -> &'tcx BorrowCheckResult<'tcx> {
-        if let Some(param_did) = def.const_param_did {
-            self.mir_borrowck_const_arg((def.did, param_did))
-        } else {
-            self.mir_borrowck(def.did)
-        }
-    }
-
+    #[inline]
     pub fn mir_const_qualif_opt_const_arg(
         self,
         def: ty::WithOptConstParam<LocalDefId>,
@@ -430,7 +425,8 @@
         }
     }
 
-    pub fn promoted_mir_of_opt_const_arg(
+    #[inline]
+    pub fn promoted_mir_opt_const_arg(
         self,
         def: ty::WithOptConstParam<DefId>,
     ) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
@@ -440,4 +436,28 @@
             self.promoted_mir(def.did)
         }
     }
+
+    #[inline]
+    pub fn optimized_mir_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<DefId>,
+    ) -> &'tcx Body<'tcx> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.optimized_mir_of_const_arg((did, param_did))
+        } else {
+            self.optimized_mir(def.did)
+        }
+    }
+
+    #[inline]
+    pub fn mir_abstract_const_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<DefId>,
+    ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.mir_abstract_const_of_const_arg((did, param_did))
+        } else {
+            self.mir_abstract_const(def.did)
+        }
+    }
 }
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index b9e4f6f..f0bfdae 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -152,10 +152,14 @@
                 tcx.mk_ty(ty::Array(operand.ty(local_decls, tcx), count))
             }
             Rvalue::ThreadLocalRef(did) => {
+                let static_ty = tcx.type_of(did);
                 if tcx.is_mutable_static(did) {
-                    tcx.mk_mut_ptr(tcx.type_of(did))
+                    tcx.mk_mut_ptr(static_ty)
+                } else if tcx.is_foreign_item(did) {
+                    tcx.mk_imm_ptr(static_ty)
                 } else {
-                    tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.type_of(did))
+                    // FIXME: These things don't *really* have 'static lifetime.
+                    tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty)
                 }
             }
             Rvalue::Ref(reg, bk, ref place) => {
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
new file mode 100644
index 0000000..c9493c6
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -0,0 +1,574 @@
+use crate::mir::interpret::Scalar;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use smallvec::{smallvec, SmallVec};
+
+use super::{
+    AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors,
+    SuccessorsMut,
+};
+pub use rustc_ast::Mutability;
+use rustc_macros::HashStable;
+use rustc_span::Span;
+use std::borrow::Cow;
+use std::fmt::{self, Debug, Formatter, Write};
+use std::iter;
+use std::slice;
+
+pub use super::query::*;
+
+#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
+pub struct SwitchTargets {
+    /// Possible values. The locations to branch to in each case
+    /// are found in the corresponding indices from the `targets` vector.
+    values: SmallVec<[u128; 1]>,
+
+    /// Possible branch sites. The last element of this vector is used
+    /// for the otherwise branch, so targets.len() == values.len() + 1
+    /// should hold.
+    //
+    // This invariant is quite non-obvious and also could be improved.
+    // One way to make this invariant is to have something like this instead:
+    //
+    // branches: Vec<(ConstInt, BasicBlock)>,
+    // otherwise: Option<BasicBlock> // exhaustive if None
+    //
+    // However we’ve decided to keep this as-is until we figure a case
+    // where some other approach seems to be strictly better than other.
+    targets: SmallVec<[BasicBlock; 2]>,
+}
+
+impl SwitchTargets {
+    /// Creates switch targets from an iterator of values and target blocks.
+    ///
+    /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
+    /// `goto otherwise;`.
+    pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self {
+        let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip();
+        targets.push(otherwise);
+        Self { values: values.into(), targets }
+    }
+
+    /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
+    /// and to `else_` if not.
+    pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self {
+        Self { values: smallvec![value], targets: smallvec![then, else_] }
+    }
+
+    /// Returns the fallback target that is jumped to when none of the values match the operand.
+    pub fn otherwise(&self) -> BasicBlock {
+        *self.targets.last().unwrap()
+    }
+
+    /// Returns an iterator over the switch targets.
+    ///
+    /// The iterator will yield tuples containing the value and corresponding target to jump to, not
+    /// including the `otherwise` fallback target.
+    ///
+    /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory.
+    pub fn iter(&self) -> SwitchTargetsIter<'_> {
+        SwitchTargetsIter { inner: self.values.iter().zip(self.targets.iter()) }
+    }
+
+    /// Returns a slice with all possible jump targets (including the fallback target).
+    pub fn all_targets(&self) -> &[BasicBlock] {
+        &self.targets
+    }
+
+    pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
+        &mut self.targets
+    }
+}
+
+pub struct SwitchTargetsIter<'a> {
+    inner: iter::Zip<slice::Iter<'a, u128>, slice::Iter<'a, BasicBlock>>,
+}
+
+impl<'a> Iterator for SwitchTargetsIter<'a> {
+    type Item = (u128, BasicBlock);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner.next().map(|(val, bb)| (*val, *bb))
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
+
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
+pub enum TerminatorKind<'tcx> {
+    /// Block should have one successor in the graph; we jump there.
+    Goto { target: BasicBlock },
+
+    /// Operand evaluates to an integer; jump depending on its value
+    /// to one of the targets, and otherwise fallback to `otherwise`.
+    SwitchInt {
+        /// The discriminant value being tested.
+        discr: Operand<'tcx>,
+
+        /// The type of value being tested.
+        /// This is always the same as the type of `discr`.
+        /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
+        switch_ty: Ty<'tcx>,
+
+        targets: SwitchTargets,
+    },
+
+    /// Indicates that the landing pad is finished and unwinding should
+    /// continue. Emitted by `build::scope::diverge_cleanup`.
+    Resume,
+
+    /// Indicates that the landing pad is finished and that the process
+    /// should abort. Used to prevent unwinding for foreign items.
+    Abort,
+
+    /// Indicates a normal return. The return place should have
+    /// been filled in before this executes. This can occur multiple times
+    /// in different basic blocks.
+    Return,
+
+    /// Indicates a terminator that can never be reached.
+    Unreachable,
+
+    /// Drop the `Place`.
+    Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
+
+    /// Drop the `Place` and assign the new value over it. This ensures
+    /// that the assignment to `P` occurs *even if* the destructor for
+    /// place unwinds. Its semantics are best explained by the
+    /// elaboration:
+    ///
+    /// ```
+    /// BB0 {
+    ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
+    /// }
+    /// ```
+    ///
+    /// becomes
+    ///
+    /// ```
+    /// BB0 {
+    ///   Drop(P, goto BB1, unwind BB2)
+    /// }
+    /// BB1 {
+    ///   // P is now uninitialized
+    ///   P <- V
+    /// }
+    /// BB2 {
+    ///   // P is now uninitialized -- its dtor panicked
+    ///   P <- V
+    /// }
+    /// ```
+    ///
+    /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass.
+    DropAndReplace {
+        place: Place<'tcx>,
+        value: Operand<'tcx>,
+        target: BasicBlock,
+        unwind: Option<BasicBlock>,
+    },
+
+    /// Block ends with a call of a function.
+    Call {
+        /// The function that’s being called.
+        func: Operand<'tcx>,
+        /// Arguments the function is called with.
+        /// These are owned by the callee, which is free to modify them.
+        /// This allows the memory occupied by "by-value" arguments to be
+        /// reused across function calls without duplicating the contents.
+        args: Vec<Operand<'tcx>>,
+        /// Destination for the return value. If some, the call is converging.
+        destination: Option<(Place<'tcx>, BasicBlock)>,
+        /// Cleanups to be done if the call unwinds.
+        cleanup: Option<BasicBlock>,
+        /// `true` if this is from a call in HIR rather than from an overloaded
+        /// operator. True for overloaded function call.
+        from_hir_call: bool,
+        /// This `Span` is the span of the function, without the dot and receiver
+        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
+        fn_span: Span,
+    },
+
+    /// Jump to the target if the condition has the expected value,
+    /// otherwise panic with a message and a cleanup target.
+    Assert {
+        cond: Operand<'tcx>,
+        expected: bool,
+        msg: AssertMessage<'tcx>,
+        target: BasicBlock,
+        cleanup: Option<BasicBlock>,
+    },
+
+    /// A suspend point.
+    Yield {
+        /// The value to return.
+        value: Operand<'tcx>,
+        /// Where to resume to.
+        resume: BasicBlock,
+        /// The place to store the resume argument in.
+        resume_arg: Place<'tcx>,
+        /// Cleanup to be done if the generator is dropped at this suspend point.
+        drop: Option<BasicBlock>,
+    },
+
+    /// Indicates the end of the dropping of a generator.
+    GeneratorDrop,
+
+    /// A block where control flow only ever takes one real path, but borrowck
+    /// needs to be more conservative.
+    FalseEdge {
+        /// The target normal control flow will take.
+        real_target: BasicBlock,
+        /// A block control flow could conceptually jump to, but won't in
+        /// practice.
+        imaginary_target: BasicBlock,
+    },
+    /// A terminator for blocks that only take one path in reality, but where we
+    /// reserve the right to unwind in borrowck, even if it won't happen in practice.
+    /// This can arise in infinite loops with no function calls for example.
+    FalseUnwind {
+        /// The target normal control flow will take.
+        real_target: BasicBlock,
+        /// The imaginary cleanup block link. This particular path will never be taken
+        /// in practice, but in order to avoid fragility we want to always
+        /// consider it in borrowck. We don't want to accept programs which
+        /// pass borrowck only when `panic=abort` or some assertions are disabled
+        /// due to release vs. debug mode builds. This needs to be an `Option` because
+        /// of the `remove_noop_landing_pads` and `no_landing_pads` passes.
+        unwind: Option<BasicBlock>,
+    },
+
+    /// Block ends with an inline assembly block. This is a terminator since
+    /// inline assembly is allowed to diverge.
+    InlineAsm {
+        /// The template for the inline assembly, with placeholders.
+        template: &'tcx [InlineAsmTemplatePiece],
+
+        /// The operands for the inline assembly, as `Operand`s or `Place`s.
+        operands: Vec<InlineAsmOperand<'tcx>>,
+
+        /// Miscellaneous options for the inline assembly.
+        options: InlineAsmOptions,
+
+        /// Source spans for each line of the inline assembly code. These are
+        /// used to map assembler errors back to the line in the source code.
+        line_spans: &'tcx [Span],
+
+        /// Destination block after the inline assembly returns, unless it is
+        /// diverging (InlineAsmOptions::NORETURN).
+        destination: Option<BasicBlock>,
+    },
+}
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct Terminator<'tcx> {
+    pub source_info: SourceInfo,
+    pub kind: TerminatorKind<'tcx>,
+}
+
+impl<'tcx> Terminator<'tcx> {
+    pub fn successors(&self) -> Successors<'_> {
+        self.kind.successors()
+    }
+
+    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
+        self.kind.successors_mut()
+    }
+
+    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
+        self.kind.unwind()
+    }
+
+    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
+        self.kind.unwind_mut()
+    }
+}
+
+impl<'tcx> TerminatorKind<'tcx> {
+    pub fn if_(
+        tcx: TyCtxt<'tcx>,
+        cond: Operand<'tcx>,
+        t: BasicBlock,
+        f: BasicBlock,
+    ) -> TerminatorKind<'tcx> {
+        TerminatorKind::SwitchInt {
+            discr: cond,
+            switch_ty: tcx.types.bool,
+            targets: SwitchTargets::static_if(0, f, t),
+        }
+    }
+
+    pub fn successors(&self) -> Successors<'_> {
+        use self::TerminatorKind::*;
+        match *self {
+            Resume
+            | Abort
+            | GeneratorDrop
+            | Return
+            | Unreachable
+            | Call { destination: None, cleanup: None, .. }
+            | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]),
+            Goto { target: ref t }
+            | Call { destination: None, cleanup: Some(ref t), .. }
+            | Call { destination: Some((_, ref t)), cleanup: None, .. }
+            | Yield { resume: ref t, drop: None, .. }
+            | DropAndReplace { target: ref t, unwind: None, .. }
+            | Drop { target: ref t, unwind: None, .. }
+            | Assert { target: ref t, cleanup: None, .. }
+            | FalseUnwind { real_target: ref t, unwind: None }
+            | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]),
+            Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
+            | Yield { resume: ref t, drop: Some(ref u), .. }
+            | DropAndReplace { target: ref t, unwind: Some(ref u), .. }
+            | Drop { target: ref t, unwind: Some(ref u), .. }
+            | Assert { target: ref t, cleanup: Some(ref u), .. }
+            | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
+                Some(t).into_iter().chain(slice::from_ref(u))
+            }
+            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets[..]),
+            FalseEdge { ref real_target, ref imaginary_target } => {
+                Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
+            }
+        }
+    }
+
+    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
+        use self::TerminatorKind::*;
+        match *self {
+            Resume
+            | Abort
+            | GeneratorDrop
+            | Return
+            | Unreachable
+            | Call { destination: None, cleanup: None, .. }
+            | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []),
+            Goto { target: ref mut t }
+            | Call { destination: None, cleanup: Some(ref mut t), .. }
+            | Call { destination: Some((_, ref mut t)), cleanup: None, .. }
+            | Yield { resume: ref mut t, drop: None, .. }
+            | DropAndReplace { target: ref mut t, unwind: None, .. }
+            | Drop { target: ref mut t, unwind: None, .. }
+            | Assert { target: ref mut t, cleanup: None, .. }
+            | FalseUnwind { real_target: ref mut t, unwind: None }
+            | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []),
+            Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
+            | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
+            | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
+            | Drop { target: ref mut t, unwind: Some(ref mut u), .. }
+            | Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
+            | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
+                Some(t).into_iter().chain(slice::from_mut(u))
+            }
+            SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets[..]),
+            FalseEdge { ref mut real_target, ref mut imaginary_target } => {
+                Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
+            }
+        }
+    }
+
+    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
+        match *self {
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Abort
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::Yield { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::InlineAsm { .. } => None,
+            TerminatorKind::Call { cleanup: ref unwind, .. }
+            | TerminatorKind::Assert { cleanup: ref unwind, .. }
+            | TerminatorKind::DropAndReplace { ref unwind, .. }
+            | TerminatorKind::Drop { ref unwind, .. }
+            | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
+        }
+    }
+
+    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
+        match *self {
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Abort
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::Yield { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::InlineAsm { .. } => None,
+            TerminatorKind::Call { cleanup: ref mut unwind, .. }
+            | TerminatorKind::Assert { cleanup: ref mut unwind, .. }
+            | TerminatorKind::DropAndReplace { ref mut unwind, .. }
+            | TerminatorKind::Drop { ref mut unwind, .. }
+            | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind),
+        }
+    }
+}
+
+impl<'tcx> Debug for TerminatorKind<'tcx> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        self.fmt_head(fmt)?;
+        let successor_count = self.successors().count();
+        let labels = self.fmt_successor_labels();
+        assert_eq!(successor_count, labels.len());
+
+        match successor_count {
+            0 => Ok(()),
+
+            1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
+
+            _ => {
+                write!(fmt, " -> [")?;
+                for (i, target) in self.successors().enumerate() {
+                    if i > 0 {
+                        write!(fmt, ", ")?;
+                    }
+                    write!(fmt, "{}: {:?}", labels[i], target)?;
+                }
+                write!(fmt, "]")
+            }
+        }
+    }
+}
+
+impl<'tcx> TerminatorKind<'tcx> {
+    /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the
+    /// successor basic block, if any. The only information not included is the list of possible
+    /// successors, which may be rendered differently between the text and the graphviz format.
+    pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
+        use self::TerminatorKind::*;
+        match self {
+            Goto { .. } => write!(fmt, "goto"),
+            SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr),
+            Return => write!(fmt, "return"),
+            GeneratorDrop => write!(fmt, "generator_drop"),
+            Resume => write!(fmt, "resume"),
+            Abort => write!(fmt, "abort"),
+            Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
+            Unreachable => write!(fmt, "unreachable"),
+            Drop { place, .. } => write!(fmt, "drop({:?})", place),
+            DropAndReplace { place, value, .. } => {
+                write!(fmt, "replace({:?} <- {:?})", place, value)
+            }
+            Call { func, args, destination, .. } => {
+                if let Some((destination, _)) = destination {
+                    write!(fmt, "{:?} = ", destination)?;
+                }
+                write!(fmt, "{:?}(", func)?;
+                for (index, arg) in args.iter().enumerate() {
+                    if index > 0 {
+                        write!(fmt, ", ")?;
+                    }
+                    write!(fmt, "{:?}", arg)?;
+                }
+                write!(fmt, ")")
+            }
+            Assert { cond, expected, msg, .. } => {
+                write!(fmt, "assert(")?;
+                if !expected {
+                    write!(fmt, "!")?;
+                }
+                write!(fmt, "{:?}, ", cond)?;
+                msg.fmt_assert_args(fmt)?;
+                write!(fmt, ")")
+            }
+            FalseEdge { .. } => write!(fmt, "falseEdge"),
+            FalseUnwind { .. } => write!(fmt, "falseUnwind"),
+            InlineAsm { template, ref operands, options, .. } => {
+                write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
+                for op in operands {
+                    write!(fmt, ", ")?;
+                    let print_late = |&late| if late { "late" } else { "" };
+                    match op {
+                        InlineAsmOperand::In { reg, value } => {
+                            write!(fmt, "in({}) {:?}", reg, value)?;
+                        }
+                        InlineAsmOperand::Out { reg, late, place: Some(place) } => {
+                            write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
+                        }
+                        InlineAsmOperand::Out { reg, late, place: None } => {
+                            write!(fmt, "{}out({}) _", print_late(late), reg)?;
+                        }
+                        InlineAsmOperand::InOut {
+                            reg,
+                            late,
+                            in_value,
+                            out_place: Some(out_place),
+                        } => {
+                            write!(
+                                fmt,
+                                "in{}out({}) {:?} => {:?}",
+                                print_late(late),
+                                reg,
+                                in_value,
+                                out_place
+                            )?;
+                        }
+                        InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => {
+                            write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
+                        }
+                        InlineAsmOperand::Const { value } => {
+                            write!(fmt, "const {:?}", value)?;
+                        }
+                        InlineAsmOperand::SymFn { value } => {
+                            write!(fmt, "sym_fn {:?}", value)?;
+                        }
+                        InlineAsmOperand::SymStatic { def_id } => {
+                            write!(fmt, "sym_static {:?}", def_id)?;
+                        }
+                    }
+                }
+                write!(fmt, ", options({:?}))", options)
+            }
+        }
+    }
+
+    /// Returns the list of labels for the edges to the successor basic blocks.
+    pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
+        use self::TerminatorKind::*;
+        match *self {
+            Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
+            Goto { .. } => vec!["".into()],
+            SwitchInt { ref targets, switch_ty, .. } => ty::tls::with(|tcx| {
+                let param_env = ty::ParamEnv::empty();
+                let switch_ty = tcx.lift(switch_ty).unwrap();
+                let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
+                targets
+                    .values
+                    .iter()
+                    .map(|&u| {
+                        ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
+                            .to_string()
+                            .into()
+                    })
+                    .chain(iter::once("otherwise".into()))
+                    .collect()
+            }),
+            Call { destination: Some(_), cleanup: Some(_), .. } => {
+                vec!["return".into(), "unwind".into()]
+            }
+            Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
+            Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+            Call { destination: None, cleanup: None, .. } => vec![],
+            Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
+            Yield { drop: None, .. } => vec!["resume".into()],
+            DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
+                vec!["return".into()]
+            }
+            DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => {
+                vec!["return".into(), "unwind".into()]
+            }
+            Assert { cleanup: None, .. } => vec!["".into()],
+            Assert { .. } => vec!["success".into(), "unwind".into()],
+            FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
+            FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
+            FalseUnwind { unwind: None, .. } => vec!["real".into()],
+            InlineAsm { destination: Some(_), .. } => vec!["".into()],
+            InlineAsm { destination: None, .. } => vec![],
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/mir/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs
deleted file mode 100644
index 8909f02..0000000
--- a/compiler/rustc_middle/src/mir/terminator/mod.rs
+++ /dev/null
@@ -1,509 +0,0 @@
-use crate::mir::interpret::Scalar;
-use crate::ty::{self, Ty, TyCtxt};
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
-
-use super::{
-    AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors,
-    SuccessorsMut,
-};
-pub use rustc_ast::Mutability;
-use rustc_macros::HashStable;
-use rustc_span::Span;
-use std::borrow::Cow;
-use std::fmt::{self, Debug, Formatter, Write};
-use std::iter;
-use std::slice;
-
-pub use super::query::*;
-
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
-pub enum TerminatorKind<'tcx> {
-    /// Block should have one successor in the graph; we jump there.
-    Goto { target: BasicBlock },
-
-    /// Operand evaluates to an integer; jump depending on its value
-    /// to one of the targets, and otherwise fallback to `otherwise`.
-    SwitchInt {
-        /// The discriminant value being tested.
-        discr: Operand<'tcx>,
-
-        /// The type of value being tested.
-        /// This is always the same as the type of `discr`.
-        /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
-        switch_ty: Ty<'tcx>,
-
-        /// Possible values. The locations to branch to in each case
-        /// are found in the corresponding indices from the `targets` vector.
-        values: Cow<'tcx, [u128]>,
-
-        /// Possible branch sites. The last element of this vector is used
-        /// for the otherwise branch, so targets.len() == values.len() + 1
-        /// should hold.
-        //
-        // This invariant is quite non-obvious and also could be improved.
-        // One way to make this invariant is to have something like this instead:
-        //
-        // branches: Vec<(ConstInt, BasicBlock)>,
-        // otherwise: Option<BasicBlock> // exhaustive if None
-        //
-        // However we’ve decided to keep this as-is until we figure a case
-        // where some other approach seems to be strictly better than other.
-        targets: Vec<BasicBlock>,
-    },
-
-    /// Indicates that the landing pad is finished and unwinding should
-    /// continue. Emitted by `build::scope::diverge_cleanup`.
-    Resume,
-
-    /// Indicates that the landing pad is finished and that the process
-    /// should abort. Used to prevent unwinding for foreign items.
-    Abort,
-
-    /// Indicates a normal return. The return place should have
-    /// been filled in before this executes. This can occur multiple times
-    /// in different basic blocks.
-    Return,
-
-    /// Indicates a terminator that can never be reached.
-    Unreachable,
-
-    /// Drop the `Place`.
-    Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
-
-    /// Drop the `Place` and assign the new value over it. This ensures
-    /// that the assignment to `P` occurs *even if* the destructor for
-    /// place unwinds. Its semantics are best explained by the
-    /// elaboration:
-    ///
-    /// ```
-    /// BB0 {
-    ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
-    /// }
-    /// ```
-    ///
-    /// becomes
-    ///
-    /// ```
-    /// BB0 {
-    ///   Drop(P, goto BB1, unwind BB2)
-    /// }
-    /// BB1 {
-    ///   // P is now uninitialized
-    ///   P <- V
-    /// }
-    /// BB2 {
-    ///   // P is now uninitialized -- its dtor panicked
-    ///   P <- V
-    /// }
-    /// ```
-    ///
-    /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass.
-    DropAndReplace {
-        place: Place<'tcx>,
-        value: Operand<'tcx>,
-        target: BasicBlock,
-        unwind: Option<BasicBlock>,
-    },
-
-    /// Block ends with a call of a function.
-    Call {
-        /// The function that’s being called.
-        func: Operand<'tcx>,
-        /// Arguments the function is called with.
-        /// These are owned by the callee, which is free to modify them.
-        /// This allows the memory occupied by "by-value" arguments to be
-        /// reused across function calls without duplicating the contents.
-        args: Vec<Operand<'tcx>>,
-        /// Destination for the return value. If some, the call is converging.
-        destination: Option<(Place<'tcx>, BasicBlock)>,
-        /// Cleanups to be done if the call unwinds.
-        cleanup: Option<BasicBlock>,
-        /// `true` if this is from a call in HIR rather than from an overloaded
-        /// operator. True for overloaded function call.
-        from_hir_call: bool,
-        /// This `Span` is the span of the function, without the dot and receiver
-        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
-        fn_span: Span,
-    },
-
-    /// Jump to the target if the condition has the expected value,
-    /// otherwise panic with a message and a cleanup target.
-    Assert {
-        cond: Operand<'tcx>,
-        expected: bool,
-        msg: AssertMessage<'tcx>,
-        target: BasicBlock,
-        cleanup: Option<BasicBlock>,
-    },
-
-    /// A suspend point.
-    Yield {
-        /// The value to return.
-        value: Operand<'tcx>,
-        /// Where to resume to.
-        resume: BasicBlock,
-        /// The place to store the resume argument in.
-        resume_arg: Place<'tcx>,
-        /// Cleanup to be done if the generator is dropped at this suspend point.
-        drop: Option<BasicBlock>,
-    },
-
-    /// Indicates the end of the dropping of a generator.
-    GeneratorDrop,
-
-    /// A block where control flow only ever takes one real path, but borrowck
-    /// needs to be more conservative.
-    FalseEdge {
-        /// The target normal control flow will take.
-        real_target: BasicBlock,
-        /// A block control flow could conceptually jump to, but won't in
-        /// practice.
-        imaginary_target: BasicBlock,
-    },
-    /// A terminator for blocks that only take one path in reality, but where we
-    /// reserve the right to unwind in borrowck, even if it won't happen in practice.
-    /// This can arise in infinite loops with no function calls for example.
-    FalseUnwind {
-        /// The target normal control flow will take.
-        real_target: BasicBlock,
-        /// The imaginary cleanup block link. This particular path will never be taken
-        /// in practice, but in order to avoid fragility we want to always
-        /// consider it in borrowck. We don't want to accept programs which
-        /// pass borrowck only when `panic=abort` or some assertions are disabled
-        /// due to release vs. debug mode builds. This needs to be an `Option` because
-        /// of the `remove_noop_landing_pads` and `no_landing_pads` passes.
-        unwind: Option<BasicBlock>,
-    },
-
-    /// Block ends with an inline assembly block. This is a terminator since
-    /// inline assembly is allowed to diverge.
-    InlineAsm {
-        /// The template for the inline assembly, with placeholders.
-        template: &'tcx [InlineAsmTemplatePiece],
-
-        /// The operands for the inline assembly, as `Operand`s or `Place`s.
-        operands: Vec<InlineAsmOperand<'tcx>>,
-
-        /// Miscellaneous options for the inline assembly.
-        options: InlineAsmOptions,
-
-        /// Source spans for each line of the inline assembly code. These are
-        /// used to map assembler errors back to the line in the source code.
-        line_spans: &'tcx [Span],
-
-        /// Destination block after the inline assembly returns, unless it is
-        /// diverging (InlineAsmOptions::NORETURN).
-        destination: Option<BasicBlock>,
-    },
-}
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
-pub struct Terminator<'tcx> {
-    pub source_info: SourceInfo,
-    pub kind: TerminatorKind<'tcx>,
-}
-
-impl<'tcx> Terminator<'tcx> {
-    pub fn successors(&self) -> Successors<'_> {
-        self.kind.successors()
-    }
-
-    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
-        self.kind.successors_mut()
-    }
-
-    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
-        self.kind.unwind()
-    }
-
-    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
-        self.kind.unwind_mut()
-    }
-}
-
-impl<'tcx> TerminatorKind<'tcx> {
-    pub fn if_(
-        tcx: TyCtxt<'tcx>,
-        cond: Operand<'tcx>,
-        t: BasicBlock,
-        f: BasicBlock,
-    ) -> TerminatorKind<'tcx> {
-        static BOOL_SWITCH_FALSE: &[u128] = &[0];
-        TerminatorKind::SwitchInt {
-            discr: cond,
-            switch_ty: tcx.types.bool,
-            values: From::from(BOOL_SWITCH_FALSE),
-            targets: vec![f, t],
-        }
-    }
-
-    pub fn successors(&self) -> Successors<'_> {
-        use self::TerminatorKind::*;
-        match *self {
-            Resume
-            | Abort
-            | GeneratorDrop
-            | Return
-            | Unreachable
-            | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]),
-            Goto { target: ref t }
-            | Call { destination: None, cleanup: Some(ref t), .. }
-            | Call { destination: Some((_, ref t)), cleanup: None, .. }
-            | Yield { resume: ref t, drop: None, .. }
-            | DropAndReplace { target: ref t, unwind: None, .. }
-            | Drop { target: ref t, unwind: None, .. }
-            | Assert { target: ref t, cleanup: None, .. }
-            | FalseUnwind { real_target: ref t, unwind: None }
-            | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]),
-            Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
-            | Yield { resume: ref t, drop: Some(ref u), .. }
-            | DropAndReplace { target: ref t, unwind: Some(ref u), .. }
-            | Drop { target: ref t, unwind: Some(ref u), .. }
-            | Assert { target: ref t, cleanup: Some(ref u), .. }
-            | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
-                Some(t).into_iter().chain(slice::from_ref(u))
-            }
-            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]),
-            FalseEdge { ref real_target, ref imaginary_target } => {
-                Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
-            }
-        }
-    }
-
-    pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
-        use self::TerminatorKind::*;
-        match *self {
-            Resume
-            | Abort
-            | GeneratorDrop
-            | Return
-            | Unreachable
-            | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []),
-            Goto { target: ref mut t }
-            | Call { destination: None, cleanup: Some(ref mut t), .. }
-            | Call { destination: Some((_, ref mut t)), cleanup: None, .. }
-            | Yield { resume: ref mut t, drop: None, .. }
-            | DropAndReplace { target: ref mut t, unwind: None, .. }
-            | Drop { target: ref mut t, unwind: None, .. }
-            | Assert { target: ref mut t, cleanup: None, .. }
-            | FalseUnwind { real_target: ref mut t, unwind: None }
-            | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []),
-            Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
-            | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
-            | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
-            | Drop { target: ref mut t, unwind: Some(ref mut u), .. }
-            | Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
-            | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
-                Some(t).into_iter().chain(slice::from_mut(u))
-            }
-            SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]),
-            FalseEdge { ref mut real_target, ref mut imaginary_target } => {
-                Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
-            }
-        }
-    }
-
-    pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
-        match *self {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm { .. } => None,
-            TerminatorKind::Call { cleanup: ref unwind, .. }
-            | TerminatorKind::Assert { cleanup: ref unwind, .. }
-            | TerminatorKind::DropAndReplace { ref unwind, .. }
-            | TerminatorKind::Drop { ref unwind, .. }
-            | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
-        }
-    }
-
-    pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
-        match *self {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::InlineAsm { .. } => None,
-            TerminatorKind::Call { cleanup: ref mut unwind, .. }
-            | TerminatorKind::Assert { cleanup: ref mut unwind, .. }
-            | TerminatorKind::DropAndReplace { ref mut unwind, .. }
-            | TerminatorKind::Drop { ref mut unwind, .. }
-            | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind),
-        }
-    }
-}
-
-impl<'tcx> Debug for TerminatorKind<'tcx> {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        self.fmt_head(fmt)?;
-        let successor_count = self.successors().count();
-        let labels = self.fmt_successor_labels();
-        assert_eq!(successor_count, labels.len());
-
-        match successor_count {
-            0 => Ok(()),
-
-            1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
-
-            _ => {
-                write!(fmt, " -> [")?;
-                for (i, target) in self.successors().enumerate() {
-                    if i > 0 {
-                        write!(fmt, ", ")?;
-                    }
-                    write!(fmt, "{}: {:?}", labels[i], target)?;
-                }
-                write!(fmt, "]")
-            }
-        }
-    }
-}
-
-impl<'tcx> TerminatorKind<'tcx> {
-    /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the
-    /// successor basic block, if any. The only information not included is the list of possible
-    /// successors, which may be rendered differently between the text and the graphviz format.
-    pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
-        use self::TerminatorKind::*;
-        match self {
-            Goto { .. } => write!(fmt, "goto"),
-            SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr),
-            Return => write!(fmt, "return"),
-            GeneratorDrop => write!(fmt, "generator_drop"),
-            Resume => write!(fmt, "resume"),
-            Abort => write!(fmt, "abort"),
-            Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
-            Unreachable => write!(fmt, "unreachable"),
-            Drop { place, .. } => write!(fmt, "drop({:?})", place),
-            DropAndReplace { place, value, .. } => {
-                write!(fmt, "replace({:?} <- {:?})", place, value)
-            }
-            Call { func, args, destination, .. } => {
-                if let Some((destination, _)) = destination {
-                    write!(fmt, "{:?} = ", destination)?;
-                }
-                write!(fmt, "{:?}(", func)?;
-                for (index, arg) in args.iter().enumerate() {
-                    if index > 0 {
-                        write!(fmt, ", ")?;
-                    }
-                    write!(fmt, "{:?}", arg)?;
-                }
-                write!(fmt, ")")
-            }
-            Assert { cond, expected, msg, .. } => {
-                write!(fmt, "assert(")?;
-                if !expected {
-                    write!(fmt, "!")?;
-                }
-                write!(fmt, "{:?}, ", cond)?;
-                msg.fmt_assert_args(fmt)?;
-                write!(fmt, ")")
-            }
-            FalseEdge { .. } => write!(fmt, "falseEdge"),
-            FalseUnwind { .. } => write!(fmt, "falseUnwind"),
-            InlineAsm { template, ref operands, options, .. } => {
-                write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?;
-                for op in operands {
-                    write!(fmt, ", ")?;
-                    let print_late = |&late| if late { "late" } else { "" };
-                    match op {
-                        InlineAsmOperand::In { reg, value } => {
-                            write!(fmt, "in({}) {:?}", reg, value)?;
-                        }
-                        InlineAsmOperand::Out { reg, late, place: Some(place) } => {
-                            write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?;
-                        }
-                        InlineAsmOperand::Out { reg, late, place: None } => {
-                            write!(fmt, "{}out({}) _", print_late(late), reg)?;
-                        }
-                        InlineAsmOperand::InOut {
-                            reg,
-                            late,
-                            in_value,
-                            out_place: Some(out_place),
-                        } => {
-                            write!(
-                                fmt,
-                                "in{}out({}) {:?} => {:?}",
-                                print_late(late),
-                                reg,
-                                in_value,
-                                out_place
-                            )?;
-                        }
-                        InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => {
-                            write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?;
-                        }
-                        InlineAsmOperand::Const { value } => {
-                            write!(fmt, "const {:?}", value)?;
-                        }
-                        InlineAsmOperand::SymFn { value } => {
-                            write!(fmt, "sym_fn {:?}", value)?;
-                        }
-                        InlineAsmOperand::SymStatic { def_id } => {
-                            write!(fmt, "sym_static {:?}", def_id)?;
-                        }
-                    }
-                }
-                write!(fmt, ", options({:?}))", options)
-            }
-        }
-    }
-
-    /// Returns the list of labels for the edges to the successor basic blocks.
-    pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
-        use self::TerminatorKind::*;
-        match *self {
-            Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
-            Goto { .. } => vec!["".into()],
-            SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| {
-                let param_env = ty::ParamEnv::empty();
-                let switch_ty = tcx.lift(&switch_ty).unwrap();
-                let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
-                values
-                    .iter()
-                    .map(|&u| {
-                        ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
-                            .to_string()
-                            .into()
-                    })
-                    .chain(iter::once("otherwise".into()))
-                    .collect()
-            }),
-            Call { destination: Some(_), cleanup: Some(_), .. } => {
-                vec!["return".into(), "unwind".into()]
-            }
-            Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
-            Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
-            Call { destination: None, cleanup: None, .. } => vec![],
-            Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
-            Yield { drop: None, .. } => vec!["resume".into()],
-            DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
-                vec!["return".into()]
-            }
-            DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => {
-                vec!["return".into(), "unwind".into()]
-            }
-            Assert { cleanup: None, .. } => vec!["".into()],
-            Assert { .. } => vec!["success".into(), "unwind".into()],
-            FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
-            FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
-            FalseUnwind { unwind: None, .. } => vec!["real".into()],
-            InlineAsm { destination: Some(_), .. } => vec!["".into()],
-            InlineAsm { destination: None, .. } => vec![],
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index ad2eae0..9297aed 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -21,10 +21,9 @@
 
         let kind = match self.kind {
             Goto { target } => Goto { target },
-            SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt {
+            SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt {
                 discr: discr.fold_with(folder),
                 switch_ty: switch_ty.fold_with(folder),
-                values: values.clone(),
                 targets: targets.clone(),
             },
             Drop { ref place, target, unwind } => {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index a008bd5..58dd0bc 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -453,7 +453,6 @@
                     TerminatorKind::SwitchInt {
                         discr,
                         switch_ty,
-                        values: _,
                         targets: _
                     } => {
                         self.visit_operand(discr, location);
@@ -752,7 +751,7 @@
             }
 
             fn super_coverage(&mut self,
-                              _kind: & $($mutability)? Coverage,
+                              _coverage: & $($mutability)? Coverage,
                               _location: Location) {
             }
 
@@ -1164,82 +1163,53 @@
 impl PlaceContext {
     /// Returns `true` if this place context represents a drop.
     pub fn is_drop(&self) -> bool {
-        match *self {
-            PlaceContext::MutatingUse(MutatingUseContext::Drop) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
     }
 
     /// Returns `true` if this place context represents a borrow.
     pub fn is_borrow(&self) -> bool {
-        match *self {
+        matches!(
+            self,
             PlaceContext::NonMutatingUse(
                 NonMutatingUseContext::SharedBorrow
-                | NonMutatingUseContext::ShallowBorrow
-                | NonMutatingUseContext::UniqueBorrow,
-            )
-            | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => true,
-            _ => false,
-        }
+                    | NonMutatingUseContext::ShallowBorrow
+                    | NonMutatingUseContext::UniqueBorrow
+            ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+        )
     }
 
     /// Returns `true` if this place context represents a storage live or storage dead marker.
     pub fn is_storage_marker(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => true,
-            _ => false,
-        }
-    }
-
-    /// Returns `true` if this place context represents a storage live marker.
-    pub fn is_storage_live_marker(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(NonUseContext::StorageLive) => true,
-            _ => false,
-        }
-    }
-
-    /// Returns `true` if this place context represents a storage dead marker.
-    pub fn is_storage_dead_marker(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(NonUseContext::StorageDead) => true,
-            _ => false,
-        }
+        matches!(
+            self,
+            PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
+        )
     }
 
     /// Returns `true` if this place context represents a use that potentially changes the value.
     pub fn is_mutating_use(&self) -> bool {
-        match *self {
-            PlaceContext::MutatingUse(..) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::MutatingUse(..))
     }
 
     /// Returns `true` if this place context represents a use that does not change the value.
     pub fn is_nonmutating_use(&self) -> bool {
-        match *self {
-            PlaceContext::NonMutatingUse(..) => true,
-            _ => false,
-        }
+        matches!(self, PlaceContext::NonMutatingUse(..))
     }
 
     /// Returns `true` if this place context represents a use.
     pub fn is_use(&self) -> bool {
-        match *self {
-            PlaceContext::NonUse(..) => false,
-            _ => true,
-        }
+        !matches!(self, PlaceContext::NonUse(..))
     }
 
     /// Returns `true` if this place context represents an assignment statement.
     pub fn is_place_assignment(&self) -> bool {
-        match *self {
+        matches!(
+            self,
             PlaceContext::MutatingUse(
                 MutatingUseContext::Store
-                | MutatingUseContext::Call
-                | MutatingUseContext::AsmOutput,
-            ) => true,
-            _ => false,
-        }
+                    | MutatingUseContext::Call
+                    | MutatingUseContext::AsmOutput,
+            )
+        )
     }
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 784d6c3..89faa97 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -92,7 +92,7 @@
         /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
         /// const argument and returns `None` otherwise.
         ///
-        /// ```rust
+        /// ```ignore (incomplete)
         /// let a = foo::<7>();
         /// //            ^ Calling `opt_const_param_of` for this argument,
         ///
@@ -156,21 +156,48 @@
             cache_on_disk_if { key.is_local() }
         }
 
-        /// Returns the list of predicates that can be used for
-        /// `SelectionCandidate::ProjectionCandidate` and
+        /// Returns the list of bounds that can be used for
+        /// `SelectionCandidate::ProjectionCandidate(_)` and
         /// `ProjectionTyCandidate::TraitDef`.
-        /// Specifically this is the bounds (equivalent to) those
-        /// written on the trait's type definition, or those
-        /// after the `impl` keyword
+        /// Specifically this is the bounds written on the trait's type
+        /// definition, or those after the `impl` keyword
         ///
+        /// ```ignore (incomplete)
         /// type X: Bound + 'lt
-        ///         ^^^^^^^^^^^
+        /// //      ^^^^^^^^^^^
         /// impl Debug + Display
-        ///      ^^^^^^^^^^^^^^^
+        /// //   ^^^^^^^^^^^^^^^
+        /// ```
         ///
         /// `key` is the `DefId` of the associated type or opaque type.
-        query projection_predicates(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
-            desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) }
+        ///
+        /// Bounds from the parent (e.g. with nested impl trait) are not included.
+        query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+            desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+        }
+
+        /// Elaborated version of the predicates from `explicit_item_bounds`.
+        ///
+        /// For example:
+        ///
+        /// ```
+        /// trait MyTrait {
+        ///     type MyAType: Eq + ?Sized;
+        /// }
+        /// ```
+        ///
+        /// `explicit_item_bounds` returns `[<Self as MyTrait>::MyAType: Eq]`,
+        /// and `item_bounds` returns
+        /// ```text
+        /// [
+        ///     <Self as Trait>::MyAType: Eq,
+        ///     <Self as Trait>::MyAType: PartialEq<<Self as Trait>::MyAType>
+        /// ]
+        /// ```
+        ///
+        /// Bounds from the parent (e.g. with nested impl trait) are not included.
+        query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+            desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
         }
 
         query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> {
@@ -191,6 +218,11 @@
             eval_always
             desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
         }
+
+        /// Internal helper query. Use `tcx.expansion_that_defined` instead
+        query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+            desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+        }
     }
 
     Codegen {
@@ -365,6 +397,24 @@
             desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
         }
 
+        /// Returns everything that looks like a predicate written explicitly
+        /// by the user on a trait item.
+        ///
+        /// Traits are unusual, because predicates on associated types are
+        /// converted into bounds on that type for backwards compatibility:
+        ///
+        /// trait X where Self::U: Copy { type U; }
+        ///
+        /// becomes
+        ///
+        /// trait X { type U: Copy; }
+        ///
+        /// `explicit_predicates_of` and `explicit_item_bounds` will then take
+        /// the appropriate subsets of the predicates here.
+        query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
+            desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
+        }
+
         /// Returns the predicates written explicitly by the user.
         query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
             desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
@@ -457,10 +507,6 @@
             desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) }
         }
 
-        query const_fn_is_allowed_fn_ptr(key: DefId) -> bool {
-            desc { |tcx| "checking if const fn allows `fn()` types: `{}`", tcx.def_path_str(key) }
-        }
-
         /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
         query is_foreign_item(key: DefId) -> bool {
             desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
@@ -1221,6 +1267,7 @@
 
     TypeChecking {
         query visibility(def_id: DefId) -> ty::Visibility {
+            eval_always
             desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
         }
     }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 1dd6d59..bbc46b8 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -13,6 +13,7 @@
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, AdtKind, Ty, TyCtxt};
 
+use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::Symbol;
@@ -342,6 +343,7 @@
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
 pub struct MatchExpressionArmCause<'tcx> {
     pub arm_span: Span,
+    pub scrut_span: Span,
     pub semi_span: Option<Span>,
     pub source: hir::MatchSource,
     pub prior_arms: Vec<Span>,
@@ -646,13 +648,13 @@
             ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
             ObjectSafetyViolation::SupertraitSelf(ref spans) => {
                 if spans.iter().any(|sp| *sp != DUMMY_SP) {
-                    "it uses `Self` as a type parameter in this".into()
+                    "it uses `Self` as a type parameter".into()
                 } else {
                     "it cannot use `Self` as a type parameter in a supertrait or `where`-clause"
                         .into()
                 }
             }
-            ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
+            ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_, _, _), _) => {
                 format!("associated function `{}` has no `self` parameter", name).into()
             }
             ObjectSafetyViolation::Method(
@@ -686,32 +688,65 @@
         }
     }
 
-    pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> {
-        Some(match *self {
-            ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {
-                return None;
+    pub fn solution(&self, err: &mut DiagnosticBuilder<'_>) {
+        match *self {
+            ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {}
+            ObjectSafetyViolation::Method(
+                name,
+                MethodViolationCode::StaticMethod(sugg, self_span, has_args),
+                _,
+            ) => {
+                err.span_suggestion(
+                    self_span,
+                    &format!(
+                        "consider turning `{}` into a method by giving it a `&self` argument",
+                        name
+                    ),
+                    format!("&self{}", if has_args { ", " } else { "" }),
+                    Applicability::MaybeIncorrect,
+                );
+                match sugg {
+                    Some((sugg, span)) => {
+                        err.span_suggestion(
+                            span,
+                            &format!(
+                                "alternatively, consider constraining `{}` so it does not apply to \
+                                 trait objects",
+                                name
+                            ),
+                            sugg.to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    None => {
+                        err.help(&format!(
+                            "consider turning `{}` into a method by giving it a `&self` \
+                             argument or constraining it so it does not apply to trait objects",
+                            name
+                        ));
+                    }
+                }
             }
-            ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => (
-                format!(
-                    "consider turning `{}` into a method by giving it a `&self` argument or \
-                     constraining it so it does not apply to trait objects",
-                    name
-                ),
-                sugg.map(|(sugg, sp)| (sugg.to_string(), sp)),
-            ),
             ObjectSafetyViolation::Method(
                 name,
                 MethodViolationCode::UndispatchableReceiver,
                 span,
-            ) => (
-                format!("consider changing method `{}`'s `self` parameter to be `&self`", name),
-                Some(("&Self".to_string(), span)),
-            ),
+            ) => {
+                err.span_suggestion(
+                    span,
+                    &format!(
+                        "consider changing method `{}`'s `self` parameter to be `&self`",
+                        name
+                    ),
+                    "&Self".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            }
             ObjectSafetyViolation::AssocConst(name, _)
             | ObjectSafetyViolation::Method(name, ..) => {
-                (format!("consider moving `{}` to another trait", name), None)
+                err.help(&format!("consider moving `{}` to another trait", name));
             }
-        })
+        }
     }
 
     pub fn spans(&self) -> SmallVec<[Span; 1]> {
@@ -735,7 +770,7 @@
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
 pub enum MethodViolationCode {
     /// e.g., `fn foo()`
-    StaticMethod(Option<(&'static str, Span)>),
+    StaticMethod(Option<(&'static str, Span)>, Span, bool /* has args */),
 
     /// e.g., `fn foo(&self, x: Self)`
     ReferencesSelfInput(usize),
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 6ad514c..c570ad3 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -105,9 +105,10 @@
     ImplCandidate(DefId),
     AutoImplCandidate(DefId),
 
-    /// This is a trait matching with a projected type as `Self`, and
-    /// we found an applicable bound in the trait definition.
-    ProjectionCandidate,
+    /// This is a trait matching with a projected type as `Self`, and we found
+    /// an applicable bound in the trait definition. The `usize` is an index
+    /// into the list returned by `tcx.item_bounds`.
+    ProjectionCandidate(usize),
 
     /// Implementation of a `Fn`-family trait by one of the anonymous types
     /// generated for a `||` expression.
@@ -126,7 +127,10 @@
 
     TraitAliasCandidate(DefId),
 
-    ObjectCandidate,
+    /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
+    /// position in the iterator returned by
+    /// `rustc_infer::traits::util::supertraits`.
+    ObjectCandidate(usize),
 
     BuiltinObjectCandidate,
 
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 969404c..ec6010e 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -79,10 +79,7 @@
 
 impl<'tcx> Node {
     pub fn is_from_trait(&self) -> bool {
-        match *self {
-            Node::Trait(..) => true,
-            _ => false,
-        }
+        matches!(self, Node::Trait(..))
     }
 
     /// Iterate over the items defined directly by the given (impl or trait) node.
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 46ef5ff..89d0e13 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -85,10 +85,7 @@
 
 impl Adjustment<'tcx> {
     pub fn is_region_borrow(&self) -> bool {
-        match self.kind {
-            Adjust::Borrow(AutoBorrow::Ref(..)) => true,
-            _ => false,
-        }
+        matches!(self.kind, Adjust::Borrow(AutoBorrow::Ref(..)))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 8ea34f9..aaf6a85 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -182,14 +182,6 @@
     where
         F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>;
 
-    fn cached_predicate_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>;
-
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R;
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 22c3fd3..ab92e5b 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -22,7 +22,7 @@
     ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntVar,
     IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
     ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
-    TyVid, TypeAndMut,
+    TyVid, TypeAndMut, Visibility,
 };
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -134,7 +134,7 @@
     fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> {
         self.predicate
             .intern(kind, |kind| {
-                let flags = super::flags::FlagComputation::for_predicate(&kind);
+                let flags = super::flags::FlagComputation::for_predicate(kind);
 
                 let predicate_struct = PredicateInner {
                     kind,
@@ -534,10 +534,6 @@
         self.node_type(pat.hir_id)
     }
 
-    pub fn pat_ty_opt(&self, pat: &hir::Pat<'_>) -> Option<Ty<'tcx>> {
-        self.node_type_opt(pat.hir_id)
-    }
-
     // Returns the type of an expression as a monotype.
     //
     // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
@@ -588,10 +584,7 @@
             return false;
         }
 
-        match self.type_dependent_defs().get(expr.hir_id) {
-            Some(Ok((DefKind::AssocFn, _))) => true,
-            _ => false,
-        }
+        matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
     }
 
     pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
@@ -918,6 +911,9 @@
     /// Common consts, pre-interned for your convenience.
     pub consts: CommonConsts<'tcx>,
 
+    /// Visibilities produced by resolver.
+    pub visibilities: FxHashMap<LocalDefId, Visibility>,
+
     /// Resolutions of `extern crate` items produced by resolver.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
 
@@ -1064,7 +1060,7 @@
         )
     }
 
-    pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
+    pub fn lift<T: Lift<'tcx>>(self, value: T) -> Option<T::Lifted> {
         value.lift_to_tcx(self)
     }
 
@@ -1086,7 +1082,7 @@
         crate_name: &str,
         output_filenames: &OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
-        let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| {
+        let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
             s.fatal(&err);
         });
         let interners = CtxtInterners::new(arena);
@@ -1131,6 +1127,7 @@
             types: common_types,
             lifetimes: common_lifetimes,
             consts: common_consts,
+            visibilities: resolutions.visibilities,
             extern_crate_map: resolutions.extern_crate_map,
             trait_map,
             export_map: resolutions.export_map,
@@ -1529,7 +1526,7 @@
     /// Determines whether identifiers in the assembly have strict naming rules.
     /// Currently, only NVPTX* targets need it.
     pub fn has_strict_asm_symbol_naming(self) -> bool {
-        self.sess.target.target.arch.contains("nvptx")
+        self.sess.target.arch.contains("nvptx")
     }
 
     /// Returns `&'static core::panic::Location<'static>`.
@@ -1572,16 +1569,16 @@
 /// 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>;
+    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 {
             type Lifted = $lifted;
-            fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-                if tcx.interners.$set.contains_pointer_to(&Interned(*self)) {
-                    Some(unsafe { mem::transmute(*self) })
+            fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+                if tcx.interners.$set.contains_pointer_to(&Interned(self)) {
+                    Some(unsafe { mem::transmute(self) })
                 } else {
                     None
                 }
@@ -1594,12 +1591,12 @@
     ($set:ident; $ty:ty => $lifted:ty) => {
         impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
             type Lifted = &'tcx List<$lifted>;
-            fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+            fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
                 if self.is_empty() {
                     return Some(List::empty());
                 }
-                if tcx.interners.$set.contains_pointer_to(&Interned(*self)) {
-                    Some(unsafe { mem::transmute(*self) })
+                if tcx.interners.$set.contains_pointer_to(&Interned(self)) {
+                    Some(unsafe { mem::transmute(self) })
                 } else {
                     None
                 }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 7153197..65703d0 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -11,21 +11,16 @@
 impl<'tcx> TyS<'tcx> {
     /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
     pub fn is_primitive_ty(&self) -> bool {
-        match self.kind() {
-            Bool
-            | Char
-            | Str
-            | Int(_)
-            | Uint(_)
-            | Float(_)
+        matches!(
+            self.kind(),
+            Bool | Char | Str | Int(_) | Uint(_) | Float(_)
             | Infer(
                 InferTy::IntVar(_)
                 | InferTy::FloatVar(_)
                 | InferTy::FreshIntTy(_)
-                | InferTy::FreshFloatTy(_),
-            ) => true,
-            _ => false,
-        }
+                | InferTy::FreshFloatTy(_)
+            )
+        )
     }
 
     /// Whether the type is succinctly representable as a type instead of just referred to with a
@@ -64,11 +59,16 @@
 
     /// Whether the type can be safely suggested during error recovery.
     pub fn is_suggestable(&self) -> bool {
-        match self.kind() {
-            Opaque(..) | FnDef(..) | FnPtr(..) | Dynamic(..) | Closure(..) | Infer(..)
-            | Projection(..) => false,
-            _ => true,
-        }
+        !matches!(
+            self.kind(),
+            Opaque(..)
+                | FnDef(..)
+                | FnPtr(..)
+                | Dynamic(..)
+                | Closure(..)
+                | Infer(..)
+                | Projection(..)
+        )
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 342a37c..235f874 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -229,10 +229,10 @@
             ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
             ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
             ty::Array(t, n) => {
-                let n = tcx.lift(&n).unwrap();
+                let n = tcx.lift(n).unwrap();
                 match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
                     _ if t.is_simple_ty() => format!("array `{}`", self).into(),
-                    Some(n) => format!("array of {} element{} ", n, pluralize!(n)).into(),
+                    Some(n) => format!("array of {} element{}", n, pluralize!(n)).into(),
                     None => "array".into(),
                 }
             }
@@ -475,6 +475,18 @@
                                  #traits-as-parameters",
                         );
                     }
+                    (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
+                        let generics = self.generics_of(body_owner_def_id);
+                        let p_span = self.def_span(generics.type_param(p, self).def_id);
+                        if !sp.contains(p_span) {
+                            db.span_label(p_span, "this type parameter");
+                        }
+                        db.help(&format!(
+                            "every closure has a distinct type and so could not always match the \
+                             caller-chosen type of parameter `{}`",
+                            p
+                        ));
+                    }
                     (ty::Param(p), _) | (_, ty::Param(p)) => {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index c9a4022..8b97a87 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -22,7 +22,7 @@
         result
     }
 
-    pub fn for_predicate(kind: &ty::PredicateKind<'_>) -> FlagComputation {
+    pub fn for_predicate(kind: ty::PredicateKind<'_>) -> FlagComputation {
         let mut result = FlagComputation::new();
         result.add_predicate_kind(kind);
         result
@@ -53,7 +53,14 @@
 
     /// Adds the flags/depth from a set of types that appear within the current type, but within a
     /// region binder.
-    fn add_bound_computation(&mut self, computation: FlagComputation) {
+    fn bound_computation<T, F>(&mut self, value: ty::Binder<T>, f: F)
+    where
+        F: FnOnce(&mut Self, T),
+    {
+        let mut computation = FlagComputation::new();
+
+        f(&mut computation, value.skip_binder());
+
         self.add_flags(computation.flags);
 
         // The types that contributed to `computation` occurred within
@@ -101,9 +108,7 @@
             }
 
             &ty::GeneratorWitness(ts) => {
-                let mut computation = FlagComputation::new();
-                computation.add_tys(ts.skip_binder());
-                self.add_bound_computation(computation);
+                self.bound_computation(ts, |flags, ts| flags.add_tys(ts));
             }
 
             &ty::Closure(_, substs) => {
@@ -154,20 +159,21 @@
                 self.add_substs(substs);
             }
 
-            &ty::Dynamic(ref obj, r) => {
-                let mut computation = FlagComputation::new();
-                for predicate in obj.skip_binder().iter() {
-                    match predicate {
-                        ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
-                        ty::ExistentialPredicate::Projection(p) => {
-                            let mut proj_computation = FlagComputation::new();
-                            proj_computation.add_existential_projection(&p);
-                            self.add_bound_computation(proj_computation);
+            &ty::Dynamic(obj, r) => {
+                self.bound_computation(obj, |computation, obj| {
+                    for predicate in obj.iter() {
+                        match predicate {
+                            ty::ExistentialPredicate::Trait(tr) => {
+                                computation.add_substs(tr.substs)
+                            }
+                            ty::ExistentialPredicate::Projection(p) => {
+                                computation.add_existential_projection(&p);
+                            }
+                            ty::ExistentialPredicate::AutoTrait(_) => {}
                         }
-                        ty::ExistentialPredicate::AutoTrait(_) => {}
                     }
-                }
-                self.add_bound_computation(computation);
+                });
+
                 self.add_region(r);
             }
 
@@ -195,22 +201,21 @@
                 self.add_substs(substs);
             }
 
-            &ty::FnPtr(f) => {
-                self.add_fn_sig(f);
-            }
+            &ty::FnPtr(fn_sig) => self.bound_computation(fn_sig, |computation, fn_sig| {
+                computation.add_tys(fn_sig.inputs());
+                computation.add_ty(fn_sig.output());
+            }),
         }
     }
 
-    fn add_predicate_kind(&mut self, kind: &ty::PredicateKind<'_>) {
+    fn add_predicate_kind(&mut self, kind: ty::PredicateKind<'_>) {
         match kind {
             ty::PredicateKind::ForAll(binder) => {
-                let mut computation = FlagComputation::new();
-
-                computation.add_predicate_atom(binder.skip_binder());
-
-                self.add_bound_computation(computation);
+                self.bound_computation(binder, |computation, atom| {
+                    computation.add_predicate_atom(atom)
+                });
             }
-            &ty::PredicateKind::Atom(atom) => self.add_predicate_atom(atom),
+            ty::PredicateKind::Atom(atom) => self.add_predicate_atom(atom),
         }
     }
 
@@ -266,15 +271,6 @@
         }
     }
 
-    fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig<'_>) {
-        let mut computation = FlagComputation::new();
-
-        computation.add_tys(fn_sig.skip_binder().inputs());
-        computation.add_ty(fn_sig.skip_binder().output());
-
-        self.add_bound_computation(computation);
-    }
-
     fn add_region(&mut self, r: ty::Region<'_>) {
         self.add_flags(r.type_flags());
         if let ty::ReLateBound(debruijn, _) = *r {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 84134be..5524d91 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -97,9 +97,6 @@
     fn has_infer_types_or_consts(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER)
     }
-    fn has_infer_consts(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_CT_INFER)
-    }
     fn needs_infer(&self) -> bool {
         self.has_type_flags(TypeFlags::NEEDS_INFER)
     }
@@ -113,9 +110,6 @@
     fn needs_subst(&self) -> bool {
         self.has_type_flags(TypeFlags::NEEDS_SUBST)
     }
-    fn has_re_placeholders(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER)
-    }
     /// "Free" regions in this context means that it has any region
     /// that is not (a) erased or (b) late-bound.
     fn has_free_regions(&self) -> bool {
@@ -719,21 +713,15 @@
 // vars. See comment on `shift_vars_through_binders` method in
 // `subst.rs` for more details.
 
-enum Direction {
-    In,
-    Out,
-}
-
 struct Shifter<'tcx> {
     tcx: TyCtxt<'tcx>,
     current_index: ty::DebruijnIndex,
     amount: u32,
-    direction: Direction,
 }
 
 impl Shifter<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, amount: u32, direction: Direction) -> Self {
-        Shifter { tcx, current_index: ty::INNERMOST, amount, direction }
+    pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self {
+        Shifter { tcx, current_index: ty::INNERMOST, amount }
     }
 }
 
@@ -755,13 +743,7 @@
                 if self.amount == 0 || debruijn < self.current_index {
                     r
                 } else {
-                    let debruijn = match self.direction {
-                        Direction::In => debruijn.shifted_in(self.amount),
-                        Direction::Out => {
-                            assert!(debruijn.as_u32() >= self.amount);
-                            debruijn.shifted_out(self.amount)
-                        }
-                    };
+                    let debruijn = debruijn.shifted_in(self.amount);
                     let shifted = ty::ReLateBound(debruijn, br);
                     self.tcx.mk_region(shifted)
                 }
@@ -776,13 +758,7 @@
                 if self.amount == 0 || debruijn < self.current_index {
                     ty
                 } else {
-                    let debruijn = match self.direction {
-                        Direction::In => debruijn.shifted_in(self.amount),
-                        Direction::Out => {
-                            assert!(debruijn.as_u32() >= self.amount);
-                            debruijn.shifted_out(self.amount)
-                        }
-                    };
+                    let debruijn = debruijn.shifted_in(self.amount);
                     self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
                 }
             }
@@ -796,13 +772,7 @@
             if self.amount == 0 || debruijn < self.current_index {
                 ct
             } else {
-                let debruijn = match self.direction {
-                    Direction::In => debruijn.shifted_in(self.amount),
-                    Direction::Out => {
-                        assert!(debruijn.as_u32() >= self.amount);
-                        debruijn.shifted_out(self.amount)
-                    }
-                };
+                let debruijn = debruijn.shifted_in(self.amount);
                 self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
             }
         } else {
@@ -830,16 +800,7 @@
 {
     debug!("shift_vars(value={:?}, amount={})", value, amount);
 
-    value.fold_with(&mut Shifter::new(tcx, amount, Direction::In))
-}
-
-pub fn shift_out_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T
-where
-    T: TypeFoldable<'tcx>,
-{
-    debug!("shift_out_vars(value={:?}, amount={})", value, amount);
-
-    value.fold_with(&mut Shifter::new(tcx, amount, Direction::Out))
+    value.fold_with(&mut Shifter::new(tcx, amount))
 }
 
 /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 2c1179c..bf1f5b8 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -104,14 +104,6 @@
         // ```
         ty.uninhabited_from(self, param_env).contains(self, module)
     }
-
-    pub fn is_ty_uninhabited_from_any_module(
-        self,
-        ty: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> bool {
-        !ty.uninhabited_from(self, param_env).is_empty()
-    }
 }
 
 impl<'tcx> AdtDef {
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index a6b6209..8b3fb87 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -22,7 +22,8 @@
     pub substs: SubstsRef<'tcx>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub enum InstanceDef<'tcx> {
     /// A user-defined callable item.
     ///
@@ -183,10 +184,10 @@
             ty::InstanceDef::DropGlue(_, Some(_)) => return false,
             _ => return true,
         };
-        match tcx.def_key(def_id).disambiguated_data.data {
-            DefPathData::Ctor | DefPathData::ClosureExpr => true,
-            _ => false,
-        }
+        matches!(
+            tcx.def_key(def_id).disambiguated_data.data,
+            DefPathData::Ctor | DefPathData::ClosureExpr
+        )
     }
 
     /// Returns `true` if the machine code for this instance is instantiated in
@@ -257,7 +258,7 @@
 impl<'tcx> fmt::Display for Instance<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         ty::tls::with(|tcx| {
-            let substs = tcx.lift(&self.substs).expect("could not lift for printing");
+            let substs = tcx.lift(self.substs).expect("could not lift for printing");
             FmtPrinter::new(tcx, &mut *f, Namespace::ValueNS)
                 .print_def_path(self.def_id(), substs)?;
             Ok(())
@@ -290,7 +291,17 @@
     }
 
     pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
-        Instance::new(def_id, tcx.empty_substs_for_def_id(def_id))
+        let substs = InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+            ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+            ty::GenericParamDefKind::Type { .. } => {
+                bug!("Instance::mono: {:?} has type parameters", def_id)
+            }
+            ty::GenericParamDefKind::Const { .. } => {
+                bug!("Instance::mono: {:?} has const parameters", def_id)
+            }
+        });
+
+        Instance::new(def_id, substs)
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index ee669ed..91c3dcb 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -106,7 +106,7 @@
         }
 
         if repr.c() {
-            match &tcx.sess.target.target.arch[..] {
+            match &tcx.sess.target.arch[..] {
                 // WARNING: the ARM EABI has two variants; the one corresponding
                 // to `at_least == I32` appears to be used on Linux and NetBSD,
                 // but some systems may use the variant corresponding to no
@@ -1894,7 +1894,7 @@
     }
 }
 
-pub type TyAndLayout<'tcx> = ::rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
+pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
 
 impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
     type Ty = Ty<'tcx>;
@@ -2548,7 +2548,7 @@
         let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
 
         use rustc_target::spec::abi::Abi::*;
-        let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) {
+        let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) {
             RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
 
             // It's the ABI's job to select this, not ours.
@@ -2600,7 +2600,7 @@
             extra_args.to_vec()
         };
 
-        let target = &cx.tcx().sess.target.target;
+        let target = &cx.tcx().sess.target;
         let target_env_gnu_like = matches!(&target.target_env[..], "gnu" | "musl");
         let win_x64_gnu =
             target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu";
@@ -2610,10 +2610,7 @@
             target.target_os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
         let linux_powerpc_gnu_like =
             target.target_os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
-        let rust_abi = match sig.abi {
-            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
-            _ => false,
-        };
+        let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
 
         // Handle safe Rust thin and fat pointers.
         let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
@@ -2778,7 +2775,7 @@
                     // anyway, we control all calls to it in libstd.
                     Abi::Vector { .. }
                         if abi != SpecAbi::PlatformIntrinsic
-                            && cx.tcx().sess.target.target.options.simd_types_indirect =>
+                            && cx.tcx().sess.target.options.simd_types_indirect =>
                     {
                         arg.make_indirect();
                         return;
@@ -2787,8 +2784,9 @@
                     _ => return,
                 }
 
-                let max_by_val_size =
-                    if is_ret { call::max_ret_by_val(cx) } else { Pointer.size(cx) };
+                // Return structures up to 2 pointers in size by value, matching `ScalarPair`. LLVM
+                // will usually return these in 2 registers, which is more efficient than by-ref.
+                let max_by_val_size = if is_ret { Pointer.size(cx) * 2 } else { Pointer.size(cx) };
                 let size = arg.layout.size;
 
                 if arg.layout.is_unsized() || size > max_by_val_size {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index d6cf68a..845fa8a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -7,7 +7,6 @@
 
 use crate::hir::exports::ExportMap;
 use crate::ich::StableHashingContext;
-use crate::infer::canonical::Canonical;
 use crate::middle::cstore::CrateStoreDyn;
 use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
 use crate::mir::interpret::ErrorHandled;
@@ -126,6 +125,7 @@
 pub struct ResolverOutputs {
     pub definitions: rustc_hir::definitions::Definitions,
     pub cstore: Box<CrateStoreDyn>,
+    pub visibilities: FxHashMap<LocalDefId, Visibility>,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -656,8 +656,6 @@
 #[rustc_diagnostic_item = "Ty"]
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
-pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>;
-
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub struct UpvarPath {
     pub hir_id: hir::HirId,
@@ -767,10 +765,6 @@
 pub struct FloatVarValue(pub ast::FloatTy);
 
 impl ty::EarlyBoundRegion {
-    pub fn to_bound_region(&self) -> ty::BoundRegion {
-        ty::BoundRegion::BrNamed(self.def_id, self.name)
-    }
-
     /// Does this early bound region have a name? Early bound regions normally
     /// always have names except when using anonymous lifetimes (`'_`).
     pub fn has_name(&self) -> bool {
@@ -821,14 +815,6 @@
             bug!("cannot convert a non-lifetime parameter def to an early bound region")
         }
     }
-
-    pub fn to_bound_region(&self) -> ty::BoundRegion {
-        if let GenericParamDefKind::Lifetime = self.kind {
-            self.to_early_bound_region_data().to_bound_region()
-        } else {
-            bug!("cannot convert a non-lifetime parameter def to an early bound region")
-        }
-    }
 }
 
 #[derive(Default)]
@@ -1003,22 +989,6 @@
         instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p));
         instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
     }
-
-    pub fn instantiate_supertrait(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        poly_trait_ref: &ty::PolyTraitRef<'tcx>,
-    ) -> InstantiatedPredicates<'tcx> {
-        assert_eq!(self.parent, None);
-        InstantiatedPredicates {
-            predicates: self
-                .predicates
-                .iter()
-                .map(|(pred, _)| pred.subst_supertrait(tcx, poly_trait_ref))
-                .collect(),
-            spans: self.predicates.iter().map(|(_, sp)| *sp).collect(),
-        }
-    }
 }
 
 #[derive(Debug)]
@@ -1087,9 +1057,21 @@
         }
     }
 
+    /// Converts this to a `Binder<PredicateAtom<'tcx>>`. If the value was an
+    /// `Atom`, then it is not allowed to contain escaping bound vars.
+    pub fn bound_atom(self) -> Binder<PredicateAtom<'tcx>> {
+        match self.kind() {
+            &PredicateKind::ForAll(binder) => binder,
+            &PredicateKind::Atom(atom) => {
+                debug_assert!(!atom.has_escaping_bound_vars());
+                Binder::dummy(atom)
+            }
+        }
+    }
+
     /// Allows using a `Binder<PredicateAtom<'tcx>>` even if the given predicate previously
     /// contained unbound variables by shifting these variables outwards.
-    pub fn bound_atom(self, tcx: TyCtxt<'tcx>) -> Binder<PredicateAtom<'tcx>> {
+    pub fn bound_atom_with_opt_escaping(self, tcx: TyCtxt<'tcx>) -> Binder<PredicateAtom<'tcx>> {
         match self.kind() {
             &PredicateKind::ForAll(binder) => binder,
             &PredicateKind::Atom(atom) => Binder::wrap_nonbinding(tcx, atom),
@@ -1303,7 +1285,6 @@
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
-pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, 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<RegionOutlivesPredicate<'tcx>>;
@@ -1751,9 +1732,6 @@
     ///
     /// Note: This is packed, use the reveal() method to access it.
     packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, traits::Reveal, true>,
-
-    /// FIXME: This field is not used, but removing it causes a performance degradation. See #76913.
-    unused_field: Option<DefId>,
 }
 
 unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
@@ -1834,7 +1812,7 @@
     /// Construct a trait environment with the given set of predicates.
     #[inline]
     pub fn new(caller_bounds: &'tcx List<Predicate<'tcx>>, reveal: Reveal) -> Self {
-        ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), unused_field: None }
+        ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) }
     }
 
     pub fn with_user_facing(mut self) -> Self {
@@ -2471,8 +2449,10 @@
         self.variants.iter().flat_map(|v| v.fields.iter())
     }
 
+    /// Whether the ADT lacks fields. Note that this includes uninhabited enums,
+    /// e.g., `enum Void {}` is considered payload free as well.
     pub fn is_payloadfree(&self) -> bool {
-        !self.variants.is_empty() && self.variants.iter().all(|v| v.fields.is_empty())
+        self.variants.iter().all(|v| v.fields.is_empty())
     }
 
     /// Return a `VariantDef` given a variant id.
@@ -2684,15 +2664,15 @@
     /// Returns `true` if a type that impls this closure kind
     /// must also implement `other`.
     pub fn extends(self, other: ty::ClosureKind) -> bool {
-        match (self, other) {
-            (ClosureKind::Fn, ClosureKind::Fn) => true,
-            (ClosureKind::Fn, ClosureKind::FnMut) => true,
-            (ClosureKind::Fn, ClosureKind::FnOnce) => true,
-            (ClosureKind::FnMut, ClosureKind::FnMut) => true,
-            (ClosureKind::FnMut, ClosureKind::FnOnce) => true,
-            (ClosureKind::FnOnce, ClosureKind::FnOnce) => true,
-            _ => false,
-        }
+        matches!(
+            (self, other),
+            (ClosureKind::Fn, ClosureKind::Fn)
+                | (ClosureKind::Fn, ClosureKind::FnMut)
+                | (ClosureKind::Fn, ClosureKind::FnOnce)
+                | (ClosureKind::FnMut, ClosureKind::FnMut)
+                | (ClosureKind::FnMut, ClosureKind::FnOnce)
+                | (ClosureKind::FnOnce, ClosureKind::FnOnce)
+        )
     }
 
     /// Returns the representative scalar type for this closure kind.
@@ -2818,15 +2798,15 @@
 
     pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
         let is_associated_item = if let Some(def_id) = def_id.as_local() {
-            match self.hir().get(self.hir().local_def_id_to_hir_id(def_id)) {
-                Node::TraitItem(_) | Node::ImplItem(_) => true,
-                _ => false,
-            }
+            matches!(
+                self.hir().get(self.hir().local_def_id_to_hir_id(def_id)),
+                Node::TraitItem(_) | Node::ImplItem(_)
+            )
         } else {
-            match self.def_kind(def_id) {
-                DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => true,
-                _ => false,
-            }
+            matches!(
+                self.def_kind(def_id),
+                DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy
+            )
         };
 
         is_associated_item.then(|| self.associated_item(def_id))
@@ -2956,13 +2936,7 @@
     /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
     pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         match instance {
-            ty::InstanceDef::Item(def) => {
-                if let Some((did, param_did)) = def.as_const_arg() {
-                    self.optimized_mir_of_const_arg((did, param_did))
-                } else {
-                    self.optimized_mir(def.did)
-                }
-            }
+            ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def),
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::Intrinsic(..)
@@ -3037,10 +3011,12 @@
                 .hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id))
     }
 
-    fn expansion_that_defined(self, scope: DefId) -> ExpnId {
+    pub fn expansion_that_defined(self, scope: DefId) -> ExpnId {
         match scope.as_local() {
+            // Parsing and expansion aren't incremental, so we don't
+            // need to go through a query for the same-crate case.
             Some(scope) => self.hir().definitions().expansion_that_defined(scope),
-            None => ExpnId::root(),
+            None => self.expn_that_defined(scope),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 48a62b6..a594a8a 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -23,7 +23,7 @@
     {
         debug!(
             "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             value,
             param_env,
         );
diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs
index ca992d3..86750d5 100644
--- a/compiler/rustc_middle/src/ty/outlives.rs
+++ b/compiler/rustc_middle/src/ty/outlives.rs
@@ -4,7 +4,7 @@
 
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc_data_structures::mini_set::MiniSet;
+use rustc_data_structures::sso::SsoHashSet;
 use smallvec::SmallVec;
 
 #[derive(Debug)]
@@ -51,7 +51,7 @@
     /// Push onto `out` all the things that must outlive `'a` for the condition
     /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
     pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) {
-        let mut visited = MiniSet::new();
+        let mut visited = SsoHashSet::new();
         compute_components(self, ty0, out, &mut visited);
         debug!("components({:?}) = {:?}", ty0, out);
     }
@@ -61,7 +61,7 @@
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     out: &mut SmallVec<[Component<'tcx>; 4]>,
-    visited: &mut MiniSet<GenericArg<'tcx>>,
+    visited: &mut SsoHashSet<GenericArg<'tcx>>,
 ) {
     // Descend through the types, looking for the various "base"
     // components and collecting them into `out`. This is not written
@@ -96,16 +96,14 @@
             }
 
             ty::Closure(_, ref substs) => {
-                for upvar_ty in substs.as_closure().upvar_tys() {
-                    compute_components(tcx, upvar_ty, out, visited);
-                }
+                let tupled_ty = substs.as_closure().tupled_upvars_ty();
+                compute_components(tcx, tupled_ty, out, visited);
             }
 
             ty::Generator(_, ref substs, _) => {
                 // Same as the closure case
-                for upvar_ty in substs.as_generator().upvar_tys() {
-                    compute_components(tcx, upvar_ty, out, visited);
-                }
+                let tupled_ty = substs.as_generator().tupled_upvars_ty();
+                compute_components(tcx, tupled_ty, out, visited);
 
                 // We ignore regions in the generator interior as we don't
                 // want these to affect region inference
@@ -142,7 +140,7 @@
                     // OutlivesProjectionComponents.  Continue walking
                     // through and constrain Pi.
                     let mut subcomponents = smallvec![];
-                    let mut subvisited = MiniSet::new();
+                    let mut subvisited = SsoHashSet::new();
                     compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
                     out.push(Component::EscapingProjection(subcomponents.into_iter().collect()));
                 }
@@ -194,7 +192,7 @@
     tcx: TyCtxt<'tcx>,
     parent: GenericArg<'tcx>,
     out: &mut SmallVec<[Component<'tcx>; 4]>,
-    visited: &mut MiniSet<GenericArg<'tcx>>,
+    visited: &mut SsoHashSet<GenericArg<'tcx>>,
 ) {
     for child in parent.walk_shallow(visited) {
         match child.unpack() {
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 225ea23..2e00be2 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -2,7 +2,7 @@
 use crate::ty::{self, DefIdTree, Ty, TyCtxt};
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::mini_set::MiniSet;
+use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 
@@ -269,7 +269,7 @@
 /// deeply nested tuples that have no DefId.
 fn characteristic_def_id_of_type_cached<'a>(
     ty: Ty<'a>,
-    visited: &mut MiniSet<Ty<'a>>,
+    visited: &mut SsoHashSet<Ty<'a>>,
 ) -> Option<DefId> {
     match *ty.kind() {
         ty::Adt(adt_def, _) => Some(adt_def.did),
@@ -316,7 +316,7 @@
     }
 }
 pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
-    characteristic_def_id_of_type_cached(ty, &mut MiniSet::new())
+    characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
 }
 
 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index cfc4b06..de24322 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -28,6 +28,9 @@
 use super::*;
 
 macro_rules! p {
+    (@$lit:literal) => {
+        write!(scoped_cx!(), $lit)?
+    };
     (@write($($data:expr),+)) => {
         write!(scoped_cx!(), $($data),+)?
     };
@@ -37,8 +40,8 @@
     (@$method:ident($($arg:expr),*)) => {
         scoped_cx!() = scoped_cx!().$method($($arg),*)?
     };
-    ($($kind:ident $data:tt),+) => {{
-        $(p!(@$kind $data);)+
+    ($($elem:tt $(($($args:tt)*))?),+) => {{
+        $(p!(@ $elem $(($($args)*))?);)+
     }};
 }
 macro_rules! define_scoped_cx {
@@ -478,7 +481,7 @@
 
             p!(print(self_ty));
             if let Some(trait_ref) = trait_ref {
-                p!(write(" as "), print(trait_ref.print_only_trait_path()));
+                p!(" as ", print(trait_ref.print_only_trait_path()));
             }
             Ok(cx)
         })
@@ -495,9 +498,9 @@
         self.generic_delimiters(|mut cx| {
             define_scoped_cx!(cx);
 
-            p!(write("impl "));
+            p!("impl ");
             if let Some(trait_ref) = trait_ref {
-                p!(print(trait_ref.print_only_trait_path()), write(" for "));
+                p!(print(trait_ref.print_only_trait_path()), " for ");
             }
             p!(print(self_ty));
 
@@ -509,8 +512,8 @@
         define_scoped_cx!(self);
 
         match *ty.kind() {
-            ty::Bool => p!(write("bool")),
-            ty::Char => p!(write("char")),
+            ty::Bool => p!("bool"),
+            ty::Char => p!("char"),
             ty::Int(t) => p!(write("{}", t.name_str())),
             ty::Uint(t) => p!(write("{}", t.name_str())),
             ty::Float(t) => p!(write("{}", t.name_str())),
@@ -525,23 +528,23 @@
                 p!(print(tm.ty))
             }
             ty::Ref(r, ty, mutbl) => {
-                p!(write("&"));
+                p!("&");
                 if self.region_should_not_be_omitted(r) {
-                    p!(print(r), write(" "));
+                    p!(print(r), " ");
                 }
                 p!(print(ty::TypeAndMut { ty, mutbl }))
             }
-            ty::Never => p!(write("!")),
+            ty::Never => p!("!"),
             ty::Tuple(ref tys) => {
-                p!(write("("), comma_sep(tys.iter()));
+                p!("(", comma_sep(tys.iter()));
                 if tys.len() == 1 {
-                    p!(write(","));
+                    p!(",");
                 }
-                p!(write(")"))
+                p!(")")
             }
             ty::FnDef(def_id, substs) => {
                 let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
-                p!(print(sig), write(" {{"), print_value_path(def_id, substs), write("}}"));
+                p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
             }
             ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
             ty::Infer(infer_ty) => {
@@ -555,7 +558,7 @@
                     p!(write("{}", infer_ty))
                 }
             }
-            ty::Error(_) => p!(write("[type error]")),
+            ty::Error(_) => p!("[type error]"),
             ty::Param(ref param_ty) => p!(write("{}", param_ty)),
             ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
                 ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
@@ -567,11 +570,11 @@
             ty::Dynamic(data, r) => {
                 let print_r = self.region_should_not_be_omitted(r);
                 if print_r {
-                    p!(write("("));
+                    p!("(");
                 }
-                p!(write("dyn "), print(data));
+                p!("dyn ", print(data));
                 if print_r {
-                    p!(write(" + "), print(r), write(")"));
+                    p!(" + ", print(r), ")");
                 }
             }
             ty::Foreign(def_id) => {
@@ -597,27 +600,27 @@
                         p!(write("{}", name));
                         // FIXME(eddyb) print this with `print_def_path`.
                         if !substs.is_empty() {
-                            p!(write("::"));
+                            p!("::");
                             p!(generic_delimiters(|cx| cx.comma_sep(substs.iter())));
                         }
                         return Ok(self);
                     }
                     // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                     // by looking up the projections associated with the def_id.
-                    let bounds = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
+                    let bounds = self.tcx().explicit_item_bounds(def_id);
 
                     let mut first = true;
                     let mut is_sized = false;
-                    p!(write("impl"));
-                    for predicate in bounds.predicates {
+                    p!("impl");
+                    for (predicate, _) in bounds {
+                        let predicate = predicate.subst(self.tcx(), substs);
                         // Note: We can't use `to_opt_poly_trait_ref` here as `predicate`
                         // may contain unbound variables. We therefore do this manually.
                         //
                         // FIXME(lcnr): Find out why exactly this is the case :)
-                        if let ty::PredicateAtom::Trait(pred, _) =
-                            predicate.bound_atom(self.tcx()).skip_binder()
-                        {
-                            let trait_ref = ty::Binder::bind(pred.trait_ref);
+                        let bound_predicate = predicate.bound_atom_with_opt_escaping(self.tcx());
+                        if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() {
+                            let trait_ref = bound_predicate.rebind(pred.trait_ref);
                             // Don't print +Sized, but rather +?Sized if absent.
                             if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
                                 is_sized = true;
@@ -634,131 +637,101 @@
                     if !is_sized {
                         p!(write("{}?Sized", if first { " " } else { "+" }));
                     } else if first {
-                        p!(write(" Sized"));
+                        p!(" Sized");
                     }
                     Ok(self)
                 })?);
             }
-            ty::Str => p!(write("str")),
+            ty::Str => p!("str"),
             ty::Generator(did, substs, movability) => {
+                p!(write("["));
                 match movability {
-                    hir::Movability::Movable => p!(write("[generator")),
-                    hir::Movability::Static => p!(write("[static generator")),
+                    hir::Movability::Movable => {}
+                    hir::Movability::Static => p!("static "),
                 }
 
-                // FIXME(eddyb) should use `def_span`.
-                if let Some(did) = did.as_local() {
-                    let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
-                    let span = self.tcx().hir().span(hir_id);
-                    p!(write("@{}", self.tcx().sess.source_map().span_to_string(span)));
-
-                    if substs.as_generator().is_valid() {
-                        let upvar_tys = substs.as_generator().upvar_tys();
-                        let mut sep = " ";
-                        for (&var_id, upvar_ty) in self
-                            .tcx()
-                            .upvars_mentioned(did)
-                            .as_ref()
-                            .iter()
-                            .flat_map(|v| v.keys())
-                            .zip(upvar_tys)
-                        {
-                            p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
-                            sep = ", ";
-                        }
+                if !self.tcx().sess.verbose() {
+                    p!("generator");
+                    // FIXME(eddyb) should use `def_span`.
+                    if let Some(did) = did.as_local() {
+                        let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
+                        let span = self.tcx().hir().span(hir_id);
+                        p!(write("@{}", self.tcx().sess.source_map().span_to_string(span)));
+                    } else {
+                        p!(write("@{}", self.tcx().def_path_str(did)));
                     }
                 } else {
-                    p!(write("@{}", self.tcx().def_path_str(did)));
-
-                    if substs.as_generator().is_valid() {
-                        let upvar_tys = substs.as_generator().upvar_tys();
-                        let mut sep = " ";
-                        for (index, upvar_ty) in upvar_tys.enumerate() {
-                            p!(write("{}{}:", sep, index), print(upvar_ty));
-                            sep = ", ";
-                        }
+                    p!(print_def_path(did, substs));
+                    p!(" upvar_tys=(");
+                    if !substs.as_generator().is_valid() {
+                        p!("unavailable");
+                    } else {
+                        self = self.comma_sep(substs.as_generator().upvar_tys())?;
                     }
+                    p!(")");
                 }
 
                 if substs.as_generator().is_valid() {
-                    p!(write(" "), print(substs.as_generator().witness()));
+                    p!(" ", print(substs.as_generator().witness()));
                 }
 
-                p!(write("]"))
+                p!("]")
             }
             ty::GeneratorWitness(types) => {
                 p!(in_binder(&types));
             }
             ty::Closure(did, substs) => {
-                p!(write("[closure"));
-
-                // FIXME(eddyb) should use `def_span`.
-                if let Some(did) = did.as_local() {
-                    let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
-                    if self.tcx().sess.opts.debugging_opts.span_free_formats {
-                        p!(write("@"), print_def_path(did.to_def_id(), substs));
-                    } else {
-                        let span = self.tcx().hir().span(hir_id);
-                        p!(write("@{}", self.tcx().sess.source_map().span_to_string(span)));
-                    }
-
-                    if substs.as_closure().is_valid() {
-                        let upvar_tys = substs.as_closure().upvar_tys();
-                        let mut sep = " ";
-                        for (&var_id, upvar_ty) in self
-                            .tcx()
-                            .upvars_mentioned(did)
-                            .as_ref()
-                            .iter()
-                            .flat_map(|v| v.keys())
-                            .zip(upvar_tys)
-                        {
-                            p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty));
-                            sep = ", ";
+                p!(write("["));
+                if !self.tcx().sess.verbose() {
+                    p!(write("closure"));
+                    // FIXME(eddyb) should use `def_span`.
+                    if let Some(did) = did.as_local() {
+                        let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
+                        if self.tcx().sess.opts.debugging_opts.span_free_formats {
+                            p!("@", print_def_path(did.to_def_id(), substs));
+                        } else {
+                            let span = self.tcx().hir().span(hir_id);
+                            p!(write("@{}", self.tcx().sess.source_map().span_to_string(span)));
                         }
+                    } else {
+                        p!(write("@{}", self.tcx().def_path_str(did)));
                     }
                 } else {
-                    p!(write("@{}", self.tcx().def_path_str(did)));
-
-                    if substs.as_closure().is_valid() {
-                        let upvar_tys = substs.as_closure().upvar_tys();
-                        let mut sep = " ";
-                        for (index, upvar_ty) in upvar_tys.enumerate() {
-                            p!(write("{}{}:", sep, index), print(upvar_ty));
-                            sep = ", ";
-                        }
+                    p!(print_def_path(did, substs));
+                    if !substs.as_closure().is_valid() {
+                        p!(" closure_substs=(unavailable)");
+                    } else {
+                        p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
+                        p!(
+                            " closure_sig_as_fn_ptr_ty=",
+                            print(substs.as_closure().sig_as_fn_ptr_ty())
+                        );
+                        p!(" upvar_tys=(");
+                        self = self.comma_sep(substs.as_closure().upvar_tys())?;
+                        p!(")");
                     }
                 }
-
-                if self.tcx().sess.verbose() && substs.as_closure().is_valid() {
-                    p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty()));
-                    p!(
-                        write(" closure_sig_as_fn_ptr_ty="),
-                        print(substs.as_closure().sig_as_fn_ptr_ty())
-                    );
-                }
-
-                p!(write("]"))
+                p!("]");
             }
             ty::Array(ty, sz) => {
-                p!(write("["), print(ty), write("; "));
+                p!("[", print(ty), "; ");
                 if self.tcx().sess.verbose() {
                     p!(write("{:?}", sz));
                 } else if let ty::ConstKind::Unevaluated(..) = sz.val {
                     // Do not try to evaluate unevaluated constants. If we are const evaluating an
                     // array length anon const, rustc will (with debug assertions) print the
                     // constant's path. Which will end up here again.
-                    p!(write("_"));
+                    p!("_");
                 } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) {
                     p!(write("{}", n));
                 } else if let ty::ConstKind::Param(param) = sz.val {
                     p!(write("{}", param));
                 } else {
-                    p!(write("_"));
+                    p!("_");
                 }
-                p!(write("]"))
+                p!("]")
             }
-            ty::Slice(ty) => p!(write("["), print(ty), write("]")),
+            ty::Slice(ty) => p!("[", print(ty), "]"),
         }
 
         Ok(self)
@@ -865,7 +838,7 @@
 
         for (_, def_id) in auto_traits {
             if !first {
-                p!(write(" + "));
+                p!(" + ");
             }
             first = false;
 
@@ -883,16 +856,16 @@
     ) -> Result<Self, Self::Error> {
         define_scoped_cx!(self);
 
-        p!(write("("), comma_sep(inputs.iter().copied()));
+        p!("(", comma_sep(inputs.iter().copied()));
         if c_variadic {
             if !inputs.is_empty() {
-                p!(write(", "));
+                p!(", ");
             }
-            p!(write("..."));
+            p!("...");
         }
-        p!(write(")"));
+        p!(")");
         if !output.is_unit() {
-            p!(write(" -> "), print(output));
+            p!(" -> ", print(output));
         }
 
         Ok(self)
@@ -963,7 +936,7 @@
                 self.pretty_print_bound_var(debruijn, bound_var)?
             }
             ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
-            ty::ConstKind::Error(_) => p!(write("[const error]")),
+            ty::ConstKind::Error(_) => p!("[const error]"),
         };
         Ok(self)
     }
@@ -1005,17 +978,17 @@
                     {
                         p!(pretty_print_byte_str(byte_str))
                     } else {
-                        p!(write("<too short allocation>"))
+                        p!("<too short allocation>")
                     }
                 }
                 // FIXME: for statics and functions, we could in principle print more detail.
                 Some(GlobalAlloc::Static(def_id)) => p!(write("<static({:?})>", def_id)),
-                Some(GlobalAlloc::Function(_)) => p!(write("<function>")),
-                None => p!(write("<dangling pointer>")),
+                Some(GlobalAlloc::Function(_)) => p!("<function>"),
+                None => p!("<dangling pointer>"),
             },
             // Bool
-            (Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")),
-            (Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")),
+            (Scalar::Raw { data: 0, .. }, ty::Bool) => p!("false"),
+            (Scalar::Raw { data: 1, .. }, ty::Bool) => p!("true"),
             // Float
             (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F32)) => {
                 p!(write("{}f32", Single::from_bits(data)))
@@ -1111,13 +1084,13 @@
 
     fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
         define_scoped_cx!(self);
-        p!(write("b\""));
+        p!("b\"");
         for &c in byte_str {
             for e in std::ascii::escape_default(c) {
                 self.write_char(e as char)?;
             }
         }
-        p!(write("\""));
+        p!("\"");
         Ok(self)
     }
 
@@ -1130,7 +1103,7 @@
         define_scoped_cx!(self);
 
         if self.tcx().sess.verbose() {
-            p!(write("ConstValue({:?}: ", ct), print(ty), write(")"));
+            p!(write("ConstValue({:?}: ", ct), print(ty), ")");
             return Ok(self);
         }
 
@@ -1156,7 +1129,7 @@
                 // relocations (we have an active `str` reference here). We don't use this
                 // result to affect interpreter execution.
                 let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
-                let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
+                let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
                 p!(write("{:?}", s));
                 Ok(self)
             }
@@ -1167,7 +1140,7 @@
                 let ptr = Pointer::new(AllocId(0), offset);
 
                 let byte_str = alloc.get_bytes(&self.tcx(), ptr, n).unwrap();
-                p!(write("*"));
+                p!("*");
                 p!(pretty_print_byte_str(byte_str));
                 Ok(self)
             }
@@ -1191,14 +1164,14 @@
 
                 match *ty.kind() {
                     ty::Array(..) => {
-                        p!(write("["), comma_sep(fields), write("]"));
+                        p!("[", comma_sep(fields), "]");
                     }
                     ty::Tuple(..) => {
-                        p!(write("("), comma_sep(fields));
+                        p!("(", comma_sep(fields));
                         if contents.fields.len() == 1 {
-                            p!(write(","));
+                            p!(",");
                         }
-                        p!(write(")"));
+                        p!(")");
                     }
                     ty::Adt(def, substs) if def.variants.is_empty() => {
                         p!(print_value_path(def.did, substs));
@@ -1212,19 +1185,19 @@
                         match variant_def.ctor_kind {
                             CtorKind::Const => {}
                             CtorKind::Fn => {
-                                p!(write("("), comma_sep(fields), write(")"));
+                                p!("(", comma_sep(fields), ")");
                             }
                             CtorKind::Fictive => {
-                                p!(write(" {{ "));
+                                p!(" {{ ");
                                 let mut first = true;
                                 for (field_def, field) in variant_def.fields.iter().zip(fields) {
                                     if !first {
-                                        p!(write(", "));
+                                        p!(", ");
                                     }
                                     p!(write("{}: ", field_def.ident), print(field));
                                     first = false;
                                 }
-                                p!(write(" }}"));
+                                p!(" }}");
                             }
                         }
                     }
@@ -1242,7 +1215,7 @@
                 // fallback
                 p!(write("{:?}", ct));
                 if print_ty {
-                    p!(write(": "), print(ty));
+                    p!(": ", print(ty));
                 }
                 Ok(self)
             }
@@ -1655,7 +1628,7 @@
             if this.print_alloc_ids {
                 p!(write("{:?}", p));
             } else {
-                p!(write("&_"));
+                p!("&_");
             }
             Ok(this)
         };
@@ -1721,11 +1694,11 @@
             ty::ReVar(_) => {}
             ty::ReErased => {}
             ty::ReStatic => {
-                p!(write("'static"));
+                p!("'static");
                 return Ok(self);
             }
             ty::ReEmpty(ty::UniverseIndex::ROOT) => {
-                p!(write("'<empty>"));
+                p!("'<empty>");
                 return Ok(self);
             }
             ty::ReEmpty(ui) => {
@@ -1734,7 +1707,7 @@
             }
         }
 
-        p!(write("'_"));
+        p!("'_");
 
         Ok(self)
     }
@@ -1865,7 +1838,7 @@
     type Error = P::Error;
     fn print(&self, mut cx: P) -> Result<Self::Output, Self::Error> {
         define_scoped_cx!(cx);
-        p!(print(self.0), write(": "), print(self.1));
+        p!(print(self.0), ": ", print(self.1));
         Ok(cx)
     }
 }
@@ -1875,7 +1848,7 @@
         $(impl fmt::Display for $ty {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 ty::tls::with(|tcx| {
-                    tcx.lift(self)
+                    tcx.lift(*self)
                         .expect("could not lift for printing")
                         .print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?;
                     Ok(())
@@ -1963,7 +1936,7 @@
     (self, cx):
 
     &'tcx ty::List<Ty<'tcx>> {
-        p!(write("{{"), comma_sep(self.iter()), write("}}"))
+        p!("{{", comma_sep(self.iter()), "}}")
     }
 
     ty::TypeAndMut<'tcx> {
@@ -1999,7 +1972,7 @@
             p!(write("extern {} ", self.abi));
         }
 
-        p!(write("fn"), pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
+        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
     }
 
     ty::InferTy {
@@ -2008,7 +1981,7 @@
             return Ok(cx);
         }
         match *self {
-            ty::TyVar(_) => p!(write("_")),
+            ty::TyVar(_) => p!("_"),
             ty::IntVar(_) => p!(write("{}", "{integer}")),
             ty::FloatVar(_) => p!(write("{}", "{float}")),
             ty::FreshTy(v) => p!(write("FreshTy({})", v)),
@@ -2034,16 +2007,16 @@
     }
 
     ty::SubtypePredicate<'tcx> {
-        p!(print(self.a), write(" <: "), print(self.b))
+        p!(print(self.a), " <: ", print(self.b))
     }
 
     ty::TraitPredicate<'tcx> {
-        p!(print(self.trait_ref.self_ty()), write(": "),
+        p!(print(self.trait_ref.self_ty()), ": ",
            print(self.trait_ref.print_only_trait_path()))
     }
 
     ty::ProjectionPredicate<'tcx> {
-        p!(print(self.projection_ty), write(" == "), print(self.ty))
+        p!(print(self.projection_ty), " == ", print(self.ty))
     }
 
     ty::ProjectionTy<'tcx> {
@@ -2052,9 +2025,9 @@
 
     ty::ClosureKind {
         match *self {
-            ty::ClosureKind::Fn => p!(write("Fn")),
-            ty::ClosureKind::FnMut => p!(write("FnMut")),
-            ty::ClosureKind::FnOnce => p!(write("FnOnce")),
+            ty::ClosureKind::Fn => p!("Fn"),
+            ty::ClosureKind::FnMut => p!("FnMut"),
+            ty::ClosureKind::FnOnce => p!("FnOnce"),
         }
     }
 
@@ -2069,7 +2042,7 @@
         match *self {
             ty::PredicateAtom::Trait(ref data, constness) => {
                 if let hir::Constness::Const = constness {
-                    p!(write("const "));
+                    p!("const ");
                 }
                 p!(print(data))
             }
@@ -2077,33 +2050,23 @@
             ty::PredicateAtom::RegionOutlives(predicate) => p!(print(predicate)),
             ty::PredicateAtom::TypeOutlives(predicate) => p!(print(predicate)),
             ty::PredicateAtom::Projection(predicate) => p!(print(predicate)),
-            ty::PredicateAtom::WellFormed(arg) => p!(print(arg), write(" well-formed")),
+            ty::PredicateAtom::WellFormed(arg) => p!(print(arg), " well-formed"),
             ty::PredicateAtom::ObjectSafe(trait_def_id) => {
-                p!(write("the trait `"),
-                print_def_path(trait_def_id, &[]),
-                write("` is object-safe"))
+                p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
             }
             ty::PredicateAtom::ClosureKind(closure_def_id, _closure_substs, kind) => {
-                p!(write("the closure `"),
+                p!("the closure `",
                 print_value_path(closure_def_id, &[]),
                 write("` implements the trait `{}`", kind))
             }
             ty::PredicateAtom::ConstEvaluatable(def, substs) => {
-                p!(write("the constant `"),
-                print_value_path(def.did, substs),
-                write("` can be evaluated"))
+                p!("the constant `", print_value_path(def.did, substs), "` can be evaluated")
             }
             ty::PredicateAtom::ConstEquate(c1, c2) => {
-                p!(write("the constant `"),
-                print(c1),
-                write("` equals `"),
-                print(c2),
-                write("`"))
+                p!("the constant `", print(c1), "` equals `", print(c2), "`")
             }
             ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
-                p!(write("the type `"),
-                print(ty),
-                write("` is found in the environment"))
+                p!("the type `", print(ty), "` is found in the environment")
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
index b0c48a8..173e9a3 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -543,7 +543,7 @@
 // tag matches and the correct amount of bytes was read.
 fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error>
 where
-    T: Decodable<D> + Eq + ::std::fmt::Debug,
+    T: Decodable<D> + Eq + std::fmt::Debug,
     V: Decodable<D>,
     D: DecoderWithPosition,
 {
@@ -601,29 +601,6 @@
         Ok(ty)
     }
 
-    fn cached_predicate_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
-    {
-        let tcx = self.tcx();
-
-        let cache_key =
-            ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
-
-        if let Some(&pred) = tcx.pred_rcache.borrow().get(&cache_key) {
-            return Ok(pred);
-        }
-
-        let pred = or_insert_with(self)?;
-        // This may overwrite the entry, but it should overwrite with the same value.
-        tcx.pred_rcache.borrow_mut().insert_same(cache_key, pred);
-        Ok(pred)
-    }
-
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
@@ -1023,7 +1000,7 @@
     let _timer = tcx
         .sess
         .prof
-        .extra_verbose_generic_activity("encode_query_results_for", ::std::any::type_name::<Q>());
+        .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>());
 
     let state = Q::query_state(tcx);
     assert!(state.all_inactive());
diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs
index f3fa363..1a8aacc 100644
--- a/compiler/rustc_middle/src/ty/query/plumbing.rs
+++ b/compiler/rustc_middle/src/ty/query/plumbing.rs
@@ -40,7 +40,8 @@
 
     fn try_collect_active_jobs(
         &self,
-    ) -> Option<FxHashMap<QueryJobId<Self::DepKind>, QueryJobInfo<Self>>> {
+    ) -> Option<FxHashMap<QueryJobId<Self::DepKind>, QueryJobInfo<Self::DepKind, Self::Query>>>
+    {
         self.queries.try_collect_active_jobs()
     }
 
@@ -124,20 +125,23 @@
         })
     }
 
-    pub fn try_print_query_stack(handler: &Handler) {
+    pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
         eprintln!("query stack during panic:");
 
         // Be careful reyling on global state here: this code is called from
         // a panic hook, which means that the global `Handler` may be in a weird
         // state if it was responsible for triggering the panic.
+        let mut i = 0;
         ty::tls::with_context_opt(|icx| {
             if let Some(icx) = icx {
                 let query_map = icx.tcx.queries.try_collect_active_jobs();
 
                 let mut current_query = icx.query;
-                let mut i = 0;
 
                 while let Some(query) = current_query {
+                    if Some(i) == num_frames {
+                        break;
+                    }
                     let query_info =
                         if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) {
                             info
@@ -163,7 +167,11 @@
             }
         });
 
-        eprintln!("end of query stack");
+        if num_frames == None || num_frames >= Some(i) {
+            eprintln!("end of query stack");
+        } else {
+            eprintln!("we're just showing a limited slice of the query stack");
+        }
     }
 }
 
@@ -346,7 +354,7 @@
             $(pub type $name<$tcx> = $V;)*
         }
 
-        $(impl<$tcx> QueryConfig<TyCtxt<$tcx>> for queries::$name<$tcx> {
+        $(impl<$tcx> QueryConfig for queries::$name<$tcx> {
             type Key = $($K)*;
             type Value = $V;
             type Stored = <
@@ -365,7 +373,7 @@
             type Cache = query_storage!([$($modifiers)*][$($K)*, $V]);
 
             #[inline(always)]
-            fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<TyCtxt<$tcx>, Self::Cache> {
+            fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, <TyCtxt<$tcx> as QueryContext>::Query, Self::Cache> {
                 &tcx.queries.$name
             }
 
@@ -447,7 +455,7 @@
             #[inline(always)]
             #[must_use]
             pub fn $name(self, key: query_helper_param_ty!($($K)*))
-                -> <queries::$name<$tcx> as QueryConfig<TyCtxt<$tcx>>>::Stored
+                -> <queries::$name<$tcx> as QueryConfig>::Stored
             {
                 self.at(DUMMY_SP).$name(key.into_query_param())
             })*
@@ -486,7 +494,7 @@
             $($(#[$attr])*
             #[inline(always)]
             pub fn $name(self, key: query_helper_param_ty!($($K)*))
-                -> <queries::$name<$tcx> as QueryConfig<TyCtxt<$tcx>>>::Stored
+                -> <queries::$name<$tcx> as QueryConfig>::Stored
             {
                 get_query::<queries::$name<'_>, _>(self.tcx, self.span, key.into_query_param())
             })*
@@ -520,7 +528,8 @@
             fallback_extern_providers: Box<Providers>,
 
             $($(#[$attr])*  $name: QueryState<
-                TyCtxt<$tcx>,
+                crate::dep_graph::DepKind,
+                <TyCtxt<$tcx> as QueryContext>::Query,
                 <queries::$name<$tcx> as QueryAccessors<TyCtxt<'tcx>>>::Cache,
             >,)*
         }
@@ -541,7 +550,7 @@
 
             pub(crate) fn try_collect_active_jobs(
                 &self
-            ) -> Option<FxHashMap<QueryJobId<crate::dep_graph::DepKind>, QueryJobInfo<TyCtxt<'tcx>>>> {
+            ) -> Option<FxHashMap<QueryJobId<crate::dep_graph::DepKind>, QueryJobInfo<crate::dep_graph::DepKind, <TyCtxt<$tcx> as QueryContext>::Query>>> {
                 let mut jobs = FxHashMap::default();
 
                 $(
diff --git a/compiler/rustc_middle/src/ty/query/profiling_support.rs b/compiler/rustc_middle/src/ty/query/profiling_support.rs
index 4e8db31..cbcecb8 100644
--- a/compiler/rustc_middle/src/ty/query/profiling_support.rs
+++ b/compiler/rustc_middle/src/ty/query/profiling_support.rs
@@ -5,8 +5,7 @@
 use rustc_data_structures::profiling::SelfProfiler;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
-use rustc_query_system::query::QueryCache;
-use rustc_query_system::query::QueryState;
+use rustc_query_system::query::{QueryCache, QueryContext, QueryState};
 use std::fmt::Debug;
 use std::io::Write;
 
@@ -231,7 +230,7 @@
 pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
     tcx: TyCtxt<'tcx>,
     query_name: &'static str,
-    query_state: &QueryState<TyCtxt<'tcx>, C>,
+    query_state: &QueryState<crate::dep_graph::DepKind, <TyCtxt<'tcx> as QueryContext>::Query, C>,
     string_cache: &mut QueryKeyStringCache,
 ) where
     C: QueryCache,
diff --git a/compiler/rustc_middle/src/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs
index b496bf8..877f88d 100644
--- a/compiler/rustc_middle/src/ty/query/stats.rs
+++ b/compiler/rustc_middle/src/ty/query/stats.rs
@@ -1,11 +1,10 @@
 use crate::ty::query::queries;
 use crate::ty::TyCtxt;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_query_system::query::QueryCache;
-use rustc_query_system::query::QueryState;
-use rustc_query_system::query::{QueryAccessors, QueryContext};
+use rustc_query_system::query::{QueryAccessors, QueryCache, QueryContext, QueryState};
 
 use std::any::type_name;
+use std::hash::Hash;
 use std::mem;
 #[cfg(debug_assertions)]
 use std::sync::atomic::Ordering;
@@ -38,10 +37,12 @@
     local_def_id_keys: Option<usize>,
 }
 
-fn stats<CTX: QueryContext, C: QueryCache>(
-    name: &'static str,
-    map: &QueryState<CTX, C>,
-) -> QueryStats {
+fn stats<D, Q, C>(name: &'static str, map: &QueryState<D, Q, C>) -> QueryStats
+where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+    C: QueryCache,
+{
     let mut stats = QueryStats {
         name,
         #[cfg(debug_assertions)]
@@ -127,7 +128,8 @@
 
             $($(
                 queries.push(stats::<
-                    TyCtxt<'_>,
+                    crate::dep_graph::DepKind,
+                    <TyCtxt<'_> as QueryContext>::Query,
                     <queries::$name<'_> as QueryAccessors<TyCtxt<'_>>>::Cache,
                 >(
                     stringify!($name),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 597ceac..d9ec6bb 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -332,24 +332,23 @@
 // FIXME(eddyb) replace all the uses of `Option::map` with `?`.
 impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
     type Lifted = (A::Lifted, B::Lifted);
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b)))
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        Some((tcx.lift(self.0)?, tcx.lift(self.1)?))
     }
 }
 
 impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) {
     type Lifted = (A::Lifted, B::Lifted, C::Lifted);
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.0)
-            .and_then(|a| tcx.lift(&self.1).and_then(|b| tcx.lift(&self.2).map(|c| (a, b, c))))
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        Some((tcx.lift(self.0)?, tcx.lift(self.1)?, tcx.lift(self.2)?))
     }
 }
 
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
     type Lifted = Option<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
-            Some(ref x) => tcx.lift(x).map(Some),
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match self {
+            Some(x) => tcx.lift(x).map(Some),
             None => Some(None),
         }
     }
@@ -357,89 +356,72 @@
 
 impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
     type Lifted = Result<T::Lifted, E::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
-            Ok(ref x) => tcx.lift(x).map(Ok),
-            Err(ref e) => tcx.lift(e).map(Err),
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match self {
+            Ok(x) => tcx.lift(x).map(Ok),
+            Err(e) => tcx.lift(e).map(Err),
         }
     }
 }
 
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
     type Lifted = Box<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&**self).map(Box::new)
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(*self).map(Box::new)
     }
 }
 
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Rc<T> {
+impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc<T> {
     type Lifted = Rc<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&**self).map(Rc::new)
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.as_ref().clone()).map(Rc::new)
     }
 }
 
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Arc<T> {
+impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> {
     type Lifted = Arc<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&**self).map(Arc::new)
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.as_ref().clone()).map(Arc::new)
     }
 }
-
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
-    type Lifted = Vec<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        // type annotation needed to inform `projection_must_outlive`
-        let mut result: Vec<<T as Lift<'tcx>>::Lifted> = Vec::with_capacity(self.len());
-        for x in self {
-            if let Some(value) = tcx.lift(x) {
-                result.push(value);
-            } else {
-                return None;
-            }
-        }
-        Some(result)
-    }
-}
-
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> {
     type Lifted = Vec<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self[..])
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        self.into_iter().map(|v| tcx.lift(v)).collect()
     }
 }
 
 impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> {
     type Lifted = IndexVec<I, T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        self.iter().map(|e| tcx.lift(e)).collect()
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        self.into_iter().map(|e| tcx.lift(e)).collect()
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> {
     type Lifted = ty::TraitRef<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.substs).map(|substs| ty::TraitRef { def_id: self.def_id, substs })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.substs).map(|substs| ty::TraitRef { def_id: self.def_id, substs })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> {
     type Lifted = ty::ExistentialTraitRef<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, substs })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, substs })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
     type Lifted = ty::ExistentialPredicate<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match self {
             ty::ExistentialPredicate::Trait(x) => tcx.lift(x).map(ty::ExistentialPredicate::Trait),
             ty::ExistentialPredicate::Projection(x) => {
                 tcx.lift(x).map(ty::ExistentialPredicate::Projection)
             }
             ty::ExistentialPredicate::AutoTrait(def_id) => {
-                Some(ty::ExistentialPredicate::AutoTrait(*def_id))
+                Some(ty::ExistentialPredicate::AutoTrait(def_id))
             }
         }
     }
@@ -447,15 +429,15 @@
 
 impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
     type Lifted = ty::TraitPredicate<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
-        tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { trait_ref })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
+        tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate { trait_ref })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> {
     type Lifted = ty::SubtypePredicate<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::SubtypePredicate<'tcx>> {
-        tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::SubtypePredicate<'tcx>> {
+        tcx.lift((self.a, self.b)).map(|(a, b)| ty::SubtypePredicate {
             a_is_expected: self.a_is_expected,
             a,
             b,
@@ -465,33 +447,33 @@
 
 impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
     type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&(self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b))
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift((self.0, self.1)).map(|(a, b)| ty::OutlivesPredicate(a, b))
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> {
     type Lifted = ty::ProjectionTy<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionTy<'tcx>> {
-        tcx.lift(&self.substs)
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionTy<'tcx>> {
+        tcx.lift(self.substs)
             .map(|substs| ty::ProjectionTy { item_def_id: self.item_def_id, substs })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
     type Lifted = ty::ProjectionPredicate<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
-        tcx.lift(&(self.projection_ty, self.ty))
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
+        tcx.lift((self.projection_ty, self.ty))
             .map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
     type Lifted = ty::ExistentialProjection<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.substs).map(|substs| ty::ExistentialProjection {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
             substs,
-            ty: tcx.lift(&self.ty).expect("type must lift when substs do"),
+            ty: tcx.lift(self.ty).expect("type must lift when substs do"),
             item_def_id: self.item_def_id,
         })
     }
@@ -499,7 +481,7 @@
 
 impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
     type Lifted = ty::PredicateKind<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match self {
             ty::PredicateKind::ForAll(binder) => tcx.lift(binder).map(ty::PredicateKind::ForAll),
             ty::PredicateKind::Atom(atom) => tcx.lift(atom).map(ty::PredicateKind::Atom),
@@ -509,24 +491,24 @@
 
 impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> {
     type Lifted = ty::PredicateAtom<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
-            ty::PredicateAtom::Trait(ref data, constness) => {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match self {
+            ty::PredicateAtom::Trait(data, constness) => {
                 tcx.lift(data).map(|data| ty::PredicateAtom::Trait(data, constness))
             }
-            ty::PredicateAtom::Subtype(ref data) => tcx.lift(data).map(ty::PredicateAtom::Subtype),
-            ty::PredicateAtom::RegionOutlives(ref data) => {
+            ty::PredicateAtom::Subtype(data) => tcx.lift(data).map(ty::PredicateAtom::Subtype),
+            ty::PredicateAtom::RegionOutlives(data) => {
                 tcx.lift(data).map(ty::PredicateAtom::RegionOutlives)
             }
-            ty::PredicateAtom::TypeOutlives(ref data) => {
+            ty::PredicateAtom::TypeOutlives(data) => {
                 tcx.lift(data).map(ty::PredicateAtom::TypeOutlives)
             }
-            ty::PredicateAtom::Projection(ref data) => {
+            ty::PredicateAtom::Projection(data) => {
                 tcx.lift(data).map(ty::PredicateAtom::Projection)
             }
-            ty::PredicateAtom::WellFormed(ty) => tcx.lift(&ty).map(ty::PredicateAtom::WellFormed),
+            ty::PredicateAtom::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateAtom::WellFormed),
             ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => {
-                tcx.lift(&closure_substs).map(|closure_substs| {
+                tcx.lift(closure_substs).map(|closure_substs| {
                     ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind)
                 })
             }
@@ -534,13 +516,13 @@
                 Some(ty::PredicateAtom::ObjectSafe(trait_def_id))
             }
             ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
-                tcx.lift(&substs).map(|substs| ty::PredicateAtom::ConstEvaluatable(def_id, substs))
+                tcx.lift(substs).map(|substs| ty::PredicateAtom::ConstEvaluatable(def_id, substs))
             }
             ty::PredicateAtom::ConstEquate(c1, c2) => {
-                tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2))
+                tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2))
             }
             ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
-                tcx.lift(&ty).map(ty::PredicateAtom::TypeWellFormedFromEnv)
+                tcx.lift(ty).map(ty::PredicateAtom::TypeWellFormedFromEnv)
             }
         }
     }
@@ -548,61 +530,62 @@
 
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
     type Lifted = ty::Binder<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(self.as_ref().skip_binder()).map(ty::Binder::bind)
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        self.map_bound(|v| tcx.lift(v)).transpose()
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
     type Lifted = ty::ParamEnv<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.caller_bounds())
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.caller_bounds())
             .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
     }
 }
 
 impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> {
     type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.param_env).and_then(|param_env| {
-            tcx.lift(&self.value).map(|value| ty::ParamEnvAnd { param_env, value })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.param_env).and_then(|param_env| {
+            tcx.lift(self.value).map(|value| ty::ParamEnvAnd { param_env, value })
         })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
     type Lifted = ty::ClosureSubsts<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.substs).map(|substs| ty::ClosureSubsts { substs })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.substs).map(|substs| ty::ClosureSubsts { substs })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorSubsts<'a> {
     type Lifted = ty::GeneratorSubsts<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.substs).map(|substs| ty::GeneratorSubsts { substs })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.substs).map(|substs| ty::GeneratorSubsts { substs })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> {
     type Lifted = ty::adjustment::Adjustment<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.kind).and_then(|kind| {
-            tcx.lift(&self.target).map(|target| ty::adjustment::Adjustment { kind, target })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        let ty::adjustment::Adjustment { kind, target } = self;
+        tcx.lift(kind).and_then(|kind| {
+            tcx.lift(target).map(|target| ty::adjustment::Adjustment { kind, target })
         })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
     type Lifted = ty::adjustment::Adjust<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match self {
             ty::adjustment::Adjust::NeverToAny => Some(ty::adjustment::Adjust::NeverToAny),
             ty::adjustment::Adjust::Pointer(ptr) => Some(ty::adjustment::Adjust::Pointer(ptr)),
-            ty::adjustment::Adjust::Deref(ref overloaded) => {
+            ty::adjustment::Adjust::Deref(overloaded) => {
                 tcx.lift(overloaded).map(ty::adjustment::Adjust::Deref)
             }
-            ty::adjustment::Adjust::Borrow(ref autoref) => {
+            ty::adjustment::Adjust::Borrow(autoref) => {
                 tcx.lift(autoref).map(ty::adjustment::Adjust::Borrow)
             }
         }
@@ -611,8 +594,8 @@
 
 impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
     type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.region).map(|region| ty::adjustment::OverloadedDeref {
             region,
             mutbl: self.mutbl,
             span: self.span,
@@ -622,10 +605,10 @@
 
 impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> {
     type Lifted = ty::adjustment::AutoBorrow<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match self {
             ty::adjustment::AutoBorrow::Ref(r, m) => {
-                tcx.lift(&r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m))
+                tcx.lift(r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m))
             }
             ty::adjustment::AutoBorrow::RawPtr(m) => Some(ty::adjustment::AutoBorrow::RawPtr(m)),
         }
@@ -634,16 +617,16 @@
 
 impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> {
     type Lifted = ty::GenSig<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&(self.resume_ty, self.yield_ty, self.return_ty))
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift((self.resume_ty, self.yield_ty, self.return_ty))
             .map(|(resume_ty, yield_ty, return_ty)| ty::GenSig { resume_ty, yield_ty, return_ty })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> {
     type Lifted = ty::FnSig<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.inputs_and_output).map(|x| ty::FnSig {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        tcx.lift(self.inputs_and_output).map(|x| ty::FnSig {
             inputs_and_output: x,
             c_variadic: self.c_variadic,
             unsafety: self.unsafety,
@@ -654,19 +637,20 @@
 
 impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> {
     type Lifted = ty::error::ExpectedFound<T::Lifted>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.expected).and_then(|expected| {
-            tcx.lift(&self.found).map(|found| ty::error::ExpectedFound { expected, found })
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        let ty::error::ExpectedFound { expected, found } = self;
+        tcx.lift(expected).and_then(|expected| {
+            tcx.lift(found).map(|found| ty::error::ExpectedFound { expected, found })
         })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
     type Lifted = ty::error::TypeError<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         use crate::ty::error::TypeError::*;
 
-        Some(match *self {
+        Some(match self {
             Mismatch => Mismatch,
             UnsafetyMismatch(x) => UnsafetyMismatch(x),
             AbiMismatch(x) => AbiMismatch(x),
@@ -675,51 +659,51 @@
             FixedArraySize(x) => FixedArraySize(x),
             ArgCount => ArgCount,
             RegionsDoesNotOutlive(a, b) => {
-                return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
+                return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
             }
             RegionsInsufficientlyPolymorphic(a, b) => {
-                return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b));
+                return tcx.lift(b).map(|b| RegionsInsufficientlyPolymorphic(a, b));
             }
             RegionsOverlyPolymorphic(a, b) => {
-                return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b));
+                return tcx.lift(b).map(|b| RegionsOverlyPolymorphic(a, b));
             }
             RegionsPlaceholderMismatch => RegionsPlaceholderMismatch,
             IntMismatch(x) => IntMismatch(x),
             FloatMismatch(x) => FloatMismatch(x),
             Traits(x) => Traits(x),
             VariadicMismatch(x) => VariadicMismatch(x),
-            CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)),
-            CyclicConst(ct) => return tcx.lift(&ct).map(|ct| CyclicConst(ct)),
+            CyclicTy(t) => return tcx.lift(t).map(|t| CyclicTy(t)),
+            CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)),
             ProjectionMismatched(x) => ProjectionMismatched(x),
-            Sorts(ref x) => return tcx.lift(x).map(Sorts),
-            ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
-            ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
+            Sorts(x) => return tcx.lift(x).map(Sorts),
+            ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch),
+            ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch),
             IntrinsicCast => IntrinsicCast,
-            TargetFeatureCast(ref x) => TargetFeatureCast(*x),
-            ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
+            TargetFeatureCast(x) => TargetFeatureCast(x),
+            ObjectUnsafeCoercion(x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
         })
     }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
     type Lifted = ty::InstanceDef<'tcx>;
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        match *self {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        match self {
             ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)),
             ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)),
             ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)),
             ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)),
-            ty::InstanceDef::FnPtrShim(def_id, ref ty) => {
+            ty::InstanceDef::FnPtrShim(def_id, ty) => {
                 Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?))
             }
             ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)),
             ty::InstanceDef::ClosureOnceShim { call_once } => {
                 Some(ty::InstanceDef::ClosureOnceShim { call_once })
             }
-            ty::InstanceDef::DropGlue(def_id, ref ty) => {
+            ty::InstanceDef::DropGlue(def_id, ty) => {
                 Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?))
             }
-            ty::InstanceDef::CloneShim(def_id, ref ty) => {
+            ty::InstanceDef::CloneShim(def_id, ty) => {
                 Some(ty::InstanceDef::CloneShim(def_id, tcx.lift(ty)?))
             }
         }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 724ec10..0fd48d0 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -210,6 +210,18 @@
             _ => false,
         }
     }
+
+    /// Get the article ("a" or "an") to use with this type.
+    pub fn article(&self) -> &'static str {
+        match self {
+            Int(_) | Float(_) | Array(_, _) => "an",
+            Adt(def, _) if def.is_enum() => "an",
+            // This should never happen, but ICEing and causing the user's code
+            // to not compile felt too harsh.
+            Error(_) => "a",
+            _ => "a",
+        }
+    }
 }
 
 // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -656,6 +668,14 @@
         };
         tupled_upvars_ty.expect_ty().tuple_fields()
     }
+
+    #[inline]
+    pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+        match self {
+            UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(),
+            UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(),
+        }
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
@@ -695,14 +715,16 @@
         use crate::ty::ToPredicate;
         match self.skip_binder() {
             ExistentialPredicate::Trait(tr) => {
-                Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx)
+                self.rebind(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx)
             }
             ExistentialPredicate::Projection(p) => {
-                Binder(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
+                self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
             }
             ExistentialPredicate::AutoTrait(did) => {
-                let trait_ref =
-                    Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) });
+                let trait_ref = self.rebind(ty::TraitRef {
+                    def_id: did,
+                    substs: tcx.mk_substs_trait(self_ty, &[]),
+                });
                 trait_ref.without_const().to_predicate(tcx)
             }
         }
@@ -767,7 +789,7 @@
 
 impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
     pub fn principal(&self) -> Option<ty::Binder<ExistentialTraitRef<'tcx>>> {
-        self.skip_binder().principal().map(Binder::bind)
+        self.map_bound(|b| b.principal()).transpose()
     }
 
     pub fn principal_def_id(&self) -> Option<DefId> {
@@ -850,8 +872,7 @@
     }
 
     pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
-        // Note that we preserve binding levels
-        Binder(ty::TraitPredicate { trait_ref: self.skip_binder() })
+        self.map_bound(|trait_ref| ty::TraitPredicate { trait_ref })
     }
 }
 
@@ -993,6 +1014,19 @@
         Binder(f(self.0))
     }
 
+    /// 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<U> {
+        Binder(value)
+    }
+
     /// 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
@@ -1513,6 +1547,9 @@
     /// then this function would return a `exists T. T: Iterator` existential trait
     /// reference.
     pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
+        // FIXME(generic_associated_types): substs is the substs of the
+        // associated type, which should be truncated to get the correct substs
+        // for the trait.
         let def_id = tcx.associated_item(self.item_def_id).container.id();
         ty::ExistentialTraitRef { def_id, substs: self.substs }
     }
@@ -1763,10 +1800,7 @@
 
     #[inline]
     pub fn is_never(&self) -> bool {
-        match self.kind() {
-            Never => true,
-            _ => false,
-        }
+        matches!(self.kind(), Never)
     }
 
     /// Checks whether a type is definitely uninhabited. This is
@@ -1823,34 +1857,22 @@
 
     #[inline]
     pub fn is_adt(&self) -> bool {
-        match self.kind() {
-            Adt(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Adt(..))
     }
 
     #[inline]
     pub fn is_ref(&self) -> bool {
-        match self.kind() {
-            Ref(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Ref(..))
     }
 
     #[inline]
     pub fn is_ty_var(&self) -> bool {
-        match self.kind() {
-            Infer(TyVar(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(TyVar(_)))
     }
 
     #[inline]
     pub fn is_ty_infer(&self) -> bool {
-        match self.kind() {
-            Infer(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(_))
     }
 
     #[inline]
@@ -1880,20 +1902,14 @@
     #[inline]
     pub fn is_slice(&self) -> bool {
         match self.kind() {
-            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind() {
-                Slice(_) | Str => true,
-                _ => false,
-            },
+            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str),
             _ => false,
         }
     }
 
     #[inline]
     pub fn is_array(&self) -> bool {
-        match self.kind() {
-            Array(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Array(..))
     }
 
     #[inline]
@@ -1940,27 +1956,21 @@
 
     #[inline]
     pub fn is_region_ptr(&self) -> bool {
-        match self.kind() {
-            Ref(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Ref(..))
     }
 
     #[inline]
     pub fn is_mutable_ptr(&self) -> bool {
-        match self.kind() {
+        matches!(
+            self.kind(),
             RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
-            | Ref(_, _, hir::Mutability::Mut) => true,
-            _ => false,
-        }
+                | Ref(_, _, hir::Mutability::Mut)
+        )
     }
 
     #[inline]
     pub fn is_unsafe_ptr(&self) -> bool {
-        match self.kind() {
-            RawPtr(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), RawPtr(_))
     }
 
     /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
@@ -1990,35 +2000,22 @@
     /// contents are abstract to rustc.)
     #[inline]
     pub fn is_scalar(&self) -> bool {
-        match self.kind() {
-            Bool
-            | Char
-            | Int(_)
-            | Float(_)
-            | Uint(_)
+        matches!(
+            self.kind(),
+            Bool | Char | Int(_) | Float(_) | Uint(_) | FnDef(..) | FnPtr(_) | RawPtr(_)
             | Infer(IntVar(_) | FloatVar(_))
-            | FnDef(..)
-            | FnPtr(_)
-            | RawPtr(_) => true,
-            _ => false,
-        }
+        )
     }
 
     /// Returns `true` if this type is a floating point type.
     #[inline]
     pub fn is_floating_point(&self) -> bool {
-        match self.kind() {
-            Float(_) | Infer(FloatVar(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Float(_) | Infer(FloatVar(_)))
     }
 
     #[inline]
     pub fn is_trait(&self) -> bool {
-        match self.kind() {
-            Dynamic(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Dynamic(..))
     }
 
     #[inline]
@@ -2031,52 +2028,32 @@
 
     #[inline]
     pub fn is_closure(&self) -> bool {
-        match self.kind() {
-            Closure(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Closure(..))
     }
 
     #[inline]
     pub fn is_generator(&self) -> bool {
-        match self.kind() {
-            Generator(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Generator(..))
     }
 
     #[inline]
     pub fn is_integral(&self) -> bool {
-        match self.kind() {
-            Infer(IntVar(_)) | Int(_) | Uint(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
     }
 
     #[inline]
     pub fn is_fresh_ty(&self) -> bool {
-        match self.kind() {
-            Infer(FreshTy(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(FreshTy(_)))
     }
 
     #[inline]
     pub fn is_fresh(&self) -> bool {
-        match self.kind() {
-            Infer(FreshTy(_)) => true,
-            Infer(FreshIntTy(_)) => true,
-            Infer(FreshFloatTy(_)) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_)))
     }
 
     #[inline]
     pub fn is_char(&self) -> bool {
-        match self.kind() {
-            Char => true,
-            _ => false,
-        }
+        matches!(self.kind(), Char)
     }
 
     #[inline]
@@ -2086,34 +2063,22 @@
 
     #[inline]
     pub fn is_signed(&self) -> bool {
-        match self.kind() {
-            Int(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Int(_))
     }
 
     #[inline]
     pub fn is_ptr_sized_integral(&self) -> bool {
-        match self.kind() {
-            Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize))
     }
 
     #[inline]
     pub fn is_machine(&self) -> bool {
-        match self.kind() {
-            Int(..) | Uint(..) | Float(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Int(..) | Uint(..) | Float(..))
     }
 
     #[inline]
     pub fn has_concrete_skeleton(&self) -> bool {
-        match self.kind() {
-            Param(_) | Infer(_) | Error(_) => false,
-            _ => true,
-        }
+        !matches!(self.kind(), Param(_) | Infer(_) | Error(_))
     }
 
     /// Returns the type and mutability of `*ty`.
@@ -2156,26 +2121,17 @@
 
     #[inline]
     pub fn is_fn(&self) -> bool {
-        match self.kind() {
-            FnDef(..) | FnPtr(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), FnDef(..) | FnPtr(_))
     }
 
     #[inline]
     pub fn is_fn_ptr(&self) -> bool {
-        match self.kind() {
-            FnPtr(_) => true,
-            _ => false,
-        }
+        matches!(self.kind(), FnPtr(_))
     }
 
     #[inline]
     pub fn is_impl_trait(&self) -> bool {
-        match self.kind() {
-            Opaque(..) => true,
-            _ => false,
-        }
+        matches!(self.kind(), Opaque(..))
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 1bd3bcb..f04144c 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -1,6 +1,5 @@
 // Type substitutions.
 
-use crate::infer::canonical::Canonical;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
@@ -142,11 +141,11 @@
 impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
     type Lifted = GenericArg<'tcx>;
 
-    fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match self.unpack() {
-            GenericArgKind::Lifetime(lt) => tcx.lift(&lt).map(|lt| lt.into()),
-            GenericArgKind::Type(ty) => tcx.lift(&ty).map(|ty| ty.into()),
-            GenericArgKind::Const(ct) => tcx.lift(&ct).map(|ct| ct.into()),
+            GenericArgKind::Lifetime(lt) => tcx.lift(lt).map(|lt| lt.into()),
+            GenericArgKind::Type(ty) => tcx.lift(ty).map(|ty| ty.into()),
+            GenericArgKind::Const(ct) => tcx.lift(ct).map(|ct| ct.into()),
         }
     }
 }
@@ -648,8 +647,6 @@
     }
 }
 
-pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>;
-
 /// Stores the user-given substs to reach some fully qualified path
 /// (e.g., `<T>::Item` or `<T as Trait>::Item`).
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 9d5b558..86476df 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -123,10 +123,26 @@
         self_ty: Ty<'tcx>,
         mut f: F,
     ) {
+        let _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| {
+            f(did);
+            None
+        });
+    }
+
+    /// Applies function to every impl that could possibly match the self type `self_ty` and returns
+    /// the first non-none value.
+    pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
+        self,
+        def_id: DefId,
+        self_ty: Ty<'tcx>,
+        mut f: F,
+    ) -> Option<T> {
         let impls = self.trait_impls_of(def_id);
 
         for &impl_def_id in impls.blanket_impls.iter() {
-            f(impl_def_id);
+            if let result @ Some(_) = f(impl_def_id) {
+                return result;
+            }
         }
 
         // simplify_type(.., false) basically replaces type parameters and
@@ -157,14 +173,20 @@
         if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
-                    f(impl_def_id);
+                    if let result @ Some(_) = f(impl_def_id) {
+                        return result;
+                    }
                 }
             }
         } else {
             for &impl_def_id in impls.non_blanket_impls.values().flatten() {
-                f(impl_def_id);
+                if let result @ Some(_) = f(impl_def_id) {
+                    return result;
+                }
             }
         }
+
+        None
     }
 
     /// Returns an iterator containing all impls
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4127b65..4a20e1c 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -6,9 +6,9 @@
 use crate::ty::fold::TypeFolder;
 use crate::ty::layout::IntegerExt;
 use crate::ty::query::TyCtxtAt;
-use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
+use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
 use crate::ty::TyKind::*;
-use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::Float as _;
 use rustc_ast as ast;
 use rustc_attr::{self as attr, SignedInt, UnsignedInt};
@@ -341,19 +341,19 @@
     pub fn calculate_dtor(
         self,
         adt_did: DefId,
-        validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>,
+        validate: impl Fn(Self, DefId) -> Result<(), ErrorReported>,
     ) -> Option<ty::Destructor> {
         let drop_trait = self.lang_items().drop_trait()?;
         self.ensure().coherent_trait(drop_trait);
 
-        let mut dtor_did = None;
         let ty = self.type_of(adt_did);
-        self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
+        let dtor_did = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
             if let Some(item) = self.associated_items(impl_did).in_definition_order().next() {
                 if validate(self, impl_did).is_ok() {
-                    dtor_did = Some(item.def_id);
+                    return Some(item.def_id);
                 }
             }
+            None
         });
 
         Some(ty::Destructor { did: dtor_did? })
@@ -509,20 +509,6 @@
         Some(ty::Binder::bind(env_ty))
     }
 
-    /// Given the `DefId` of some item that has no type or const parameters, make
-    /// a suitable "empty substs" for it.
-    pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> {
-        InternalSubsts::for_item(self, item_def_id, |param, _| match param.kind {
-            GenericParamDefKind::Lifetime => self.lifetimes.re_erased.into(),
-            GenericParamDefKind::Type { .. } => {
-                bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
-            }
-            GenericParamDefKind::Const { .. } => {
-                bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id)
-            }
-        })
-    }
-
     /// Returns `true` if the node pointed to by `def_id` is a `static` item.
     pub fn is_static(self, def_id: DefId) -> bool {
         self.static_mutability(def_id).is_some()
@@ -543,8 +529,12 @@
         // Make sure that any constants in the static's type are evaluated.
         let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id));
 
+        // Make sure that accesses to unsafe statics end up using raw pointers.
+        // For thread-locals, this needs to be kept in sync with `Rvalue::ty`.
         if self.is_mutable_static(def_id) {
             self.mk_mut_ptr(static_ty)
+        } else if self.is_foreign_item(def_id) {
+            self.mk_imm_ptr(static_ty)
         } else {
             self.mk_imm_ref(self.lifetimes.re_erased, static_ty)
         }
@@ -646,8 +636,8 @@
             }
             ty::Char => Some(std::char::MAX as u128),
             ty::Float(fty) => Some(match fty {
-                ast::FloatTy::F32 => ::rustc_apfloat::ieee::Single::INFINITY.to_bits(),
-                ast::FloatTy::F64 => ::rustc_apfloat::ieee::Double::INFINITY.to_bits(),
+                ast::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
+                ast::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
             }),
             _ => None,
         };
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 80ade7d..357a0dd 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -3,7 +3,7 @@
 
 use crate::ty;
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use rustc_data_structures::mini_set::MiniSet;
+use rustc_data_structures::sso::SsoHashSet;
 use smallvec::{self, SmallVec};
 
 // The TypeWalker's stack is hot enough that it's worth going to some effort to
@@ -13,7 +13,7 @@
 pub struct TypeWalker<'tcx> {
     stack: TypeWalkerStack<'tcx>,
     last_subtree: usize,
-    visited: MiniSet<GenericArg<'tcx>>,
+    visited: SsoHashSet<GenericArg<'tcx>>,
 }
 
 /// An iterator for walking the type tree.
@@ -26,7 +26,7 @@
 /// skips any types that are already there.
 impl<'tcx> TypeWalker<'tcx> {
     pub fn new(root: GenericArg<'tcx>) -> Self {
-        Self { stack: smallvec![root], last_subtree: 1, visited: MiniSet::new() }
+        Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
     }
 
     /// Skips the subtree corresponding to the last type
@@ -87,7 +87,7 @@
     /// and skips any types that are already there.
     pub fn walk_shallow(
         self,
-        visited: &mut MiniSet<GenericArg<'tcx>>,
+        visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> impl Iterator<Item = GenericArg<'tcx>> {
         let mut stack = SmallVec::new();
         push_inner(&mut stack, self);
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml
index a6d2224..487668c 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_mir/Cargo.toml
@@ -12,7 +12,6 @@
 rustc_graphviz = { path = "../rustc_graphviz" }
 itertools = "0.9"
 tracing = "0.1"
-log_settings = "0.1.1"
 polonius-engine = "0.12.0"
 regex = "1"
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index 11122b1..dca0d6d 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -336,10 +336,11 @@
                 };
                 if let ty::Param(param_ty) = ty.kind() {
                     let tcx = self.infcx.tcx;
-                    let generics = tcx.generics_of(self.mir_def_id);
+                    let generics = tcx.generics_of(self.mir_def_id());
                     let param = generics.type_param(&param_ty, tcx);
-                    if let Some(generics) =
-                        tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id.to_def_id()))
+                    if let Some(generics) = tcx
+                        .hir()
+                        .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
                     {
                         suggest_constraining_type_param(
                             tcx,
@@ -1004,7 +1005,7 @@
                 format!("`{}` would have to be valid for `{}`...", name, region_name),
             );
 
-            let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
+            let fn_hir_id = self.mir_hir_id();
             err.span_label(
                 drop_span,
                 format!(
@@ -1019,7 +1020,7 @@
                             match &self
                                 .infcx
                                 .tcx
-                                .typeck(self.mir_def_id)
+                                .typeck(self.mir_def_id())
                                 .node_type(fn_hir_id)
                                 .kind()
                             {
@@ -1369,7 +1370,7 @@
     ) -> DiagnosticBuilder<'cx> {
         let tcx = self.infcx.tcx;
 
-        let (_, escapes_from) = tcx.article_and_description(self.mir_def_id.to_def_id());
+        let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id());
 
         let mut err =
             borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
@@ -1708,15 +1709,15 @@
     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
         // Define a fallback for when we can't match a closure.
         let fallback = || {
-            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id.to_def_id());
+            let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id());
             if is_closure {
                 None
             } else {
-                let ty = self.infcx.tcx.type_of(self.mir_def_id);
+                let ty = self.infcx.tcx.type_of(self.mir_def_id());
                 match ty.kind() {
                     ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
-                        self.mir_def_id.to_def_id(),
-                        self.infcx.tcx.fn_sig(self.mir_def_id),
+                        self.mir_def_id().to_def_id(),
+                        self.infcx.tcx.fn_sig(self.mir_def_id()),
                     ),
                     _ => None,
                 }
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
index 629e9be..b1cebbd 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
@@ -331,7 +331,7 @@
                 self.cannot_move_out_of_interior_noncopy(span, ty, None)
             }
             ty::Closure(def_id, closure_substs)
-                if def_id.as_local() == Some(self.mir_def_id) && upvar_field.is_some() =>
+                if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() =>
             {
                 let closure_kind_ty = closure_substs.as_closure().kind_ty();
                 let closure_kind = closure_kind_ty.to_opt_closure_kind();
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index d4cdf02..e1af6fc 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -1,11 +1,11 @@
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
-use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalInfo, Location};
+use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::source_map::DesugaringKind;
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
 use crate::borrow_check::diagnostics::BorrowedContentSource;
@@ -211,36 +211,12 @@
 
             // Suggest removing a `&mut` from the use of a mutable reference.
             PlaceRef { local, projection: [] }
-                if {
-                    self.body
-                        .local_decls
-                        .get(local)
-                        .map(|local_decl| {
-                            if let Some(box LocalInfo::User(ClearCrossCrate::Set(
-                                mir::BindingForm::ImplicitSelf(kind),
-                            ))) = local_decl.local_info
-                            {
-                                // Check if the user variable is a `&mut self` and we can therefore
-                                // suggest removing the `&mut`.
-                                //
-                                // Deliberately fall into this case for all implicit self types,
-                                // so that we don't fall in to the next case with them.
-                                kind == mir::ImplicitSelfKind::MutRef
-                            } else if Some(kw::SelfLower) == self.local_names[local] {
-                                // Otherwise, check if the name is the self kewyord - in which case
-                                // we have an explicit self. Do the same thing in this case and check
-                                // for a `self: &mut Self` to suggest removing the `&mut`.
-                                if let ty::Ref(_, _, hir::Mutability::Mut) = local_decl.ty.kind() {
-                                    true
-                                } else {
-                                    false
-                                }
-                            } else {
-                                false
-                            }
-                        })
-                        .unwrap_or(false)
-                } =>
+                if self
+                    .body
+                    .local_decls
+                    .get(local)
+                    .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local]))
+                    .unwrap_or(false) =>
             {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
                 err.span_label(span, "try removing `&mut` here");
@@ -492,7 +468,7 @@
         err.span_label(sp, format!("cannot {}", act));
 
         let hir = self.infcx.tcx.hir();
-        let closure_id = hir.local_def_id_to_hir_id(self.mir_def_id);
+        let closure_id = self.mir_hir_id();
         let fn_call_id = hir.get_parent_node(closure_id);
         let node = hir.get(fn_call_id);
         let item_id = hir.enclosing_body_owner(fn_call_id);
@@ -581,6 +557,34 @@
     }
 }
 
+fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
+    debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
+
+    match local_decl.local_info.as_deref() {
+        // Check if mutably borrowing a mutable reference.
+        Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+            mir::VarBindingForm {
+                binding_mode: ty::BindingMode::BindByValue(Mutability::Not), ..
+            },
+        )))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
+        Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => {
+            // Check if the user variable is a `&mut self` and we can therefore
+            // suggest removing the `&mut`.
+            //
+            // Deliberately fall into this case for all implicit self types,
+            // so that we don't fall in to the next case with them.
+            *kind == mir::ImplicitSelfKind::MutRef
+        }
+        _ if Some(kw::SelfLower) == local_name => {
+            // Otherwise, check if the name is the `self` keyword - in which case
+            // we have an explicit self. Do the same thing in this case and check
+            // for a `self: &mut Self` to suggest removing the `&mut`.
+            matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut))
+        }
+        _ => false,
+    }
+}
+
 fn suggest_ampmut_self<'tcx>(
     tcx: TyCtxt<'tcx>,
     local_decl: &mir::LocalDecl<'tcx>,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
index eb1f700..e22dab0 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
@@ -6,6 +6,7 @@
     error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin,
 };
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
+use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
@@ -515,7 +516,8 @@
         let mut diag =
             self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough");
 
-        let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id.to_def_id());
+        let (_, mir_def_name) =
+            self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id());
 
         let fr_name = self.give_region_a_name(*fr).unwrap();
         fr_name.highlight_region_name(&mut diag);
@@ -584,14 +586,14 @@
                 //
                 // eg. check for `impl Trait + 'static` instead of `impl Trait`.
                 let has_static_predicate = {
-                    let predicates_of = self.infcx.tcx.predicates_of(did);
-                    let bounds = predicates_of.instantiate(self.infcx.tcx, substs);
+                    let bounds = self.infcx.tcx.explicit_item_bounds(did);
 
                     let mut found = false;
-                    for predicate in bounds.predicates {
+                    for (bound, _) in bounds {
                         if let ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(_, r)) =
-                            predicate.skip_binders()
+                            bound.skip_binders()
                         {
+                            let r = r.subst(self.infcx.tcx, substs);
                             if let ty::RegionKind::ReStatic = r {
                                 found = true;
                                 break;
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
index 5f64eb3..2e5a231 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
@@ -147,6 +147,14 @@
 }
 
 impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
+    crate fn mir_def_id(&self) -> hir::def_id::LocalDefId {
+        self.body.source.def_id().as_local().unwrap()
+    }
+
+    crate fn mir_hir_id(&self) -> hir::HirId {
+        self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id())
+    }
+
     /// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then,
     /// increment the counter.
     ///
@@ -266,12 +274,11 @@
                 }
 
                 ty::BoundRegion::BrEnv => {
-                    let mir_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
                     let def_ty = self.regioncx.universal_regions().defining_ty;
 
                     if let DefiningTy::Closure(_, substs) = def_ty {
                         let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) =
-                            tcx.hir().expect_expr(mir_hir_id).kind
+                            tcx.hir().expect_expr(self.mir_hir_id()).kind
                         {
                             span
                         } else {
@@ -361,8 +368,7 @@
         &self,
         argument_index: usize,
     ) -> Option<&hir::Ty<'tcx>> {
-        let mir_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
-        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
+        let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(self.mir_hir_id())?;
         let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
         match argument_hir_ty.kind {
             // This indicates a variable with no type annotation, like
@@ -649,9 +655,7 @@
         let type_name =
             self.infcx.extract_inference_diagnostics_data(return_ty.into(), Some(highlight)).name;
 
-        let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
-
-        let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) {
+        let (return_span, mir_description) = match tcx.hir().get(self.mir_hir_id()) {
             hir::Node::Expr(hir::Expr {
                 kind: hir::ExprKind::Closure(_, return_ty, _, span, gen_move),
                 ..
@@ -702,9 +706,7 @@
         let type_name =
             self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
 
-        let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
-
-        let yield_span = match tcx.hir().get(mir_hir_id) {
+        let yield_span = match tcx.hir().get(self.mir_hir_id()) {
             hir::Node::Expr(hir::Expr {
                 kind: hir::ExprKind::Closure(_, _, _, span, _), ..
             }) => (tcx.sess.source_map().end_point(*span)),
diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs
index c84ccaf..8c05e6f 100644
--- a/compiler/rustc_mir/src/borrow_check/invalidation.rs
+++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs
@@ -117,7 +117,7 @@
         self.check_activations(location);
 
         match &terminator.kind {
-            TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
+            TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => {
                 self.consume_operand(location, discr);
             }
             TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index e423748..de54c55 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -17,7 +17,7 @@
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
 use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
@@ -36,7 +36,6 @@
 use crate::dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveError};
 use crate::dataflow::MoveDataParamEnv;
 use crate::dataflow::{Analysis, BorrowckFlowState as Flows, BorrowckResults};
-use crate::transform::MirSource;
 
 use self::diagnostics::{AccessKind, RegionName};
 use self::location::LocationTable;
@@ -112,7 +111,7 @@
     let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
-        do_mir_borrowck(&infcx, input_body, promoted, def)
+        do_mir_borrowck(&infcx, input_body, promoted)
     });
     debug!("mir_borrowck done");
 
@@ -123,8 +122,9 @@
     infcx: &InferCtxt<'a, 'tcx>,
     input_body: &Body<'tcx>,
     input_promoted: &IndexVec<Promoted, Body<'tcx>>,
-    def: ty::WithOptConstParam<LocalDefId>,
 ) -> BorrowCheckResult<'tcx> {
+    let def = input_body.source.with_opt_param().as_local().unwrap();
+
     debug!("do_mir_borrowck(def = {:?})", def);
 
     let tcx = infcx.tcx;
@@ -186,7 +186,7 @@
     // will have a lifetime tied to the inference context.
     let mut body = input_body.clone();
     let mut promoted = input_promoted.clone();
-    let free_regions = nll::replace_regions_in_mir(infcx, def, param_env, &mut body, &mut promoted);
+    let free_regions = nll::replace_regions_in_mir(infcx, param_env, &mut body, &mut promoted);
     let body = &body; // no further changes
 
     let location_table = &LocationTable::new(&body);
@@ -204,7 +204,7 @@
     let mdpe = MoveDataParamEnv { move_data, param_env };
 
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def.did.to_def_id())
+        .into_engine(tcx, &body)
         .pass_name("borrowck")
         .iterate_to_fixpoint()
         .into_results_cursor(&body);
@@ -222,7 +222,6 @@
         nll_errors,
     } = nll::compute_regions(
         infcx,
-        def.did,
         free_regions,
         body,
         &promoted,
@@ -236,20 +235,13 @@
 
     // Dump MIR results into a file, if that is enabled. This let us
     // write unit-tests, as well as helping with debugging.
-    nll::dump_mir_results(
-        infcx,
-        MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None },
-        &body,
-        &regioncx,
-        &opt_closure_req,
-    );
+    nll::dump_mir_results(infcx, &body, &regioncx, &opt_closure_req);
 
     // We also have a `#[rustc_regions]` annotation that causes us to dump
     // information.
     nll::dump_annotation(
         infcx,
         &body,
-        def.did.to_def_id(),
         &regioncx,
         &opt_closure_req,
         &opaque_type_values,
@@ -264,15 +256,15 @@
     let regioncx = Rc::new(regioncx);
 
     let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set)
-        .into_engine(tcx, &body, def.did.to_def_id())
+        .into_engine(tcx, &body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
     let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def.did.to_def_id())
+        .into_engine(tcx, &body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
     let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def.did.to_def_id())
+        .into_engine(tcx, &body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
 
@@ -293,7 +285,6 @@
                 infcx,
                 param_env,
                 body: promoted_body,
-                mir_def_id: def.did,
                 move_data: &move_data,
                 location_table: &LocationTable::new(promoted_body),
                 movable_generator,
@@ -327,7 +318,6 @@
         infcx,
         param_env,
         body,
-        mir_def_id: def.did,
         move_data: &mdpe.move_data,
         location_table,
         movable_generator,
@@ -481,7 +471,6 @@
     crate infcx: &'cx InferCtxt<'cx, 'tcx>,
     param_env: ParamEnv<'tcx>,
     body: &'cx Body<'tcx>,
-    mir_def_id: LocalDefId,
     move_data: &'cx MoveData<'tcx>,
 
     /// Map from MIR `Location` to `LocationIndex`; created
@@ -682,32 +671,19 @@
         self.check_activations(loc, span, flow_state);
 
         match term.kind {
-            TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
+            TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => {
                 self.consume_operand(loc, (discr, span), flow_state);
             }
-            TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => {
-                let tcx = self.infcx.tcx;
-
-                // Compute the type with accurate region information.
-                let drop_place_ty = drop_place.ty(self.body, self.infcx.tcx);
-
-                // Erase the regions.
-                let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty;
-
-                // "Lift" into the tcx -- once regions are erased, this type should be in the
-                // global arenas; this "lift" operation basically just asserts that is true, but
-                // that is useful later.
-                tcx.lift(&drop_place_ty).unwrap();
-
+            TerminatorKind::Drop { place, target: _, unwind: _ } => {
                 debug!(
                     "visit_terminator_drop \
-                     loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
-                    loc, term, drop_place, drop_place_ty, span
+                     loc: {:?} term: {:?} place: {:?} span: {:?}",
+                    loc, term, place, span
                 );
 
                 self.access_place(
                     loc,
-                    (*drop_place, span),
+                    (place, span),
                     (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
                     LocalMutationIsAllowed::Yes,
                     flow_state,
diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs
index 66a17cb..aa42832 100644
--- a/compiler/rustc_mir/src/borrow_check/nll.rs
+++ b/compiler/rustc_mir/src/borrow_check/nll.rs
@@ -2,14 +2,14 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::{
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
 };
-use rustc_middle::ty::{self, InstanceDef, RegionKind, RegionVid};
+use rustc_middle::ty::{self, RegionKind, RegionVid};
 use rustc_span::symbol::sym;
 use std::env;
 use std::fmt::Debug;
@@ -24,7 +24,6 @@
 use crate::dataflow::impls::MaybeInitializedPlaces;
 use crate::dataflow::move_paths::{InitKind, InitLocation, MoveData};
 use crate::dataflow::ResultsCursor;
-use crate::transform::MirSource;
 use crate::util as mir_util;
 use crate::util::pretty;
 
@@ -59,11 +58,12 @@
 /// `compute_regions`.
 pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
     param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexVec<Promoted, Body<'tcx>>,
 ) -> UniversalRegions<'tcx> {
+    let def = body.source.with_opt_param().as_local().unwrap();
+
     debug!("replace_regions_in_mir(def={:?})", def);
 
     // Compute named region information. This also renumbers the inputs/outputs.
@@ -72,8 +72,7 @@
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
 
-    let source = MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None };
-    mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
+    mir_util::dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(()));
 
     universal_regions
 }
@@ -158,7 +157,6 @@
 /// This may result in errors being reported.
 pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    def_id: LocalDefId,
     universal_regions: UniversalRegions<'tcx>,
     body: &Body<'tcx>,
     promoted: &IndexVec<Promoted, Body<'tcx>>,
@@ -182,7 +180,6 @@
             param_env,
             body,
             promoted,
-            def_id,
             &universal_regions,
             location_table,
             borrow_set,
@@ -272,10 +269,12 @@
     // Generate various additional constraints.
     invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set);
 
+    let def_id = body.source.def_id();
+
     // Dump facts if requested.
     let polonius_output = all_facts.and_then(|all_facts| {
         if infcx.tcx.sess.opts.debugging_opts.nll_facts {
-            let def_path = infcx.tcx.def_path(def_id.to_def_id());
+            let def_path = infcx.tcx.def_path(def_id);
             let dir_path =
                 PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate());
             all_facts.write_to_dir(dir_path, location_table).unwrap();
@@ -295,7 +294,7 @@
 
     // Solve the region constraints.
     let (closure_region_requirements, nll_errors) =
-        regioncx.solve(infcx, &body, def_id.to_def_id(), polonius_output.clone());
+        regioncx.solve(infcx, &body, polonius_output.clone());
 
     if !nll_errors.is_empty() {
         // Suppress unhelpful extra errors in `infer_opaque_types`.
@@ -315,16 +314,15 @@
 
 pub(super) fn dump_mir_results<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
-    source: MirSource<'tcx>,
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
 ) {
-    if !mir_util::dump_enabled(infcx.tcx, "nll", source.def_id()) {
+    if !mir_util::dump_enabled(infcx.tcx, "nll", body.source.def_id()) {
         return;
     }
 
-    mir_util::dump_mir(infcx.tcx, None, "nll", &0, source, body, |pass_where, out| {
+    mir_util::dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| {
         match pass_where {
             // Before the CFG, dump out the values for each region variable.
             PassWhere::BeforeCFG => {
@@ -352,14 +350,14 @@
     // Also dump the inference graph constraints as a graphviz file.
     let _: io::Result<()> = try {
         let mut file =
-            pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, source)?;
+            pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?;
         regioncx.dump_graphviz_raw_constraints(&mut file)?;
     };
 
     // Also dump the inference graph constraints as a graphviz file.
     let _: io::Result<()> = try {
         let mut file =
-            pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, source)?;
+            pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?;
         regioncx.dump_graphviz_scc_constraints(&mut file)?;
     };
 }
@@ -367,14 +365,13 @@
 pub(super) fn dump_annotation<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     body: &Body<'tcx>,
-    mir_def_id: DefId,
     regioncx: &RegionInferenceContext<'tcx>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
     opaque_type_values: &FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
     errors_buffer: &mut Vec<Diagnostic>,
 ) {
     let tcx = infcx.tcx;
-    let base_def_id = tcx.closure_base_def_id(mir_def_id);
+    let base_def_id = tcx.closure_base_def_id(body.source.def_id());
     if !tcx.has_attr(base_def_id, sym::rustc_regions) {
         return;
     }
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 081125c..4772663 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -548,10 +548,10 @@
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
         body: &Body<'tcx>,
-        mir_def_id: DefId,
         polonius_output: Option<Rc<PoloniusOutput>>,
     ) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
-        self.propagate_constraints(body);
+        let mir_def_id = body.source.def_id();
+        self.propagate_constraints(body, infcx.tcx);
 
         let mut errors_buffer = RegionErrors::new();
 
@@ -599,7 +599,7 @@
     /// for each region variable until all the constraints are
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
-    fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
+    fn propagate_constraints(&mut self, _body: &Body<'tcx>, tcx: TyCtxt<'tcx>) {
         debug!("propagate_constraints()");
 
         debug!("propagate_constraints: constraints={:#?}", {
@@ -617,7 +617,7 @@
         // own.
         let constraint_sccs = self.constraint_sccs.clone();
         for scc in constraint_sccs.all_sccs() {
-            self.compute_value_for_scc(scc);
+            self.compute_value_for_scc(scc, tcx);
         }
 
         // Sort the applied member constraints so we can binary search
@@ -629,7 +629,7 @@
     /// computed, by unioning the values of its successors.
     /// Assumes that all successors have been computed already
     /// (which is assured by iterating over SCCs in dependency order).
-    fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) {
+    fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex, tcx: TyCtxt<'tcx>) {
         let constraint_sccs = self.constraint_sccs.clone();
 
         // Walk each SCC `B` such that `A: B`...
@@ -652,7 +652,12 @@
         // Now take member constraints into account.
         let member_constraints = self.member_constraints.clone();
         for m_c_i in member_constraints.indices(scc_a) {
-            self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i));
+            self.apply_member_constraint(
+                tcx,
+                scc_a,
+                m_c_i,
+                member_constraints.choice_regions(m_c_i),
+            );
         }
 
         debug!(
@@ -675,6 +680,7 @@
     /// If we make any changes, returns true, else false.
     fn apply_member_constraint(
         &mut self,
+        tcx: TyCtxt<'tcx>,
         scc: ConstraintSccIndex,
         member_constraint_index: NllMemberConstraintIndex,
         choice_regions: &[ty::RegionVid],
@@ -688,12 +694,15 @@
             // `impl_trait_in_bindings`, I believe, and we are just
             // opting not to handle it for now. See #61773 for
             // details.
-            bug!(
-                "member constraint for `{:?}` has an option region `{:?}` \
-                 that is not a universal region",
-                self.member_constraints[member_constraint_index].opaque_type_def_id,
-                uh_oh,
+            tcx.sess.delay_span_bug(
+                self.member_constraints[member_constraint_index].definition_span,
+                &format!(
+                    "member constraint for `{:?}` has an option region `{:?}` \
+                     that is not a universal region",
+                    self.member_constraints[member_constraint_index].opaque_type_def_id, uh_oh,
+                ),
             );
+            return false;
         }
 
         // Create a mutable vector of the options. We'll try to winnow
@@ -1216,7 +1225,9 @@
     /// it. However, it works pretty well in practice. In particular,
     /// this is needed to deal with projection outlives bounds like
     ///
-    ///     <T as Foo<'0>>::Item: '1
+    /// ```ignore (internal compiler representation so lifetime syntax is invalid)
+    /// <T as Foo<'0>>::Item: '1
+    /// ```
     ///
     /// In particular, this routine winds up being important when
     /// there are bounds like `where <T as Foo<'a>>::Item: 'b` in the
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
index 711271a..8513e5e 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
@@ -62,8 +62,7 @@
         // `self.constraints`, but we also want to be mutating
         // `self.member_constraints`. For now, just swap out the value
         // we want and replace at the end.
-        let mut tmp =
-            std::mem::replace(&mut self.constraints.member_constraints, Default::default());
+        let mut tmp = std::mem::take(&mut self.constraints.member_constraints);
         for member_constraint in member_constraints {
             tmp.push_constraint(member_constraint, |r| self.to_region_vid(r));
         }
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
index 4846ef0..444f9fe 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
@@ -28,42 +28,43 @@
         let (&normalized_output_ty, normalized_input_tys) =
             normalized_inputs_and_output.split_last().unwrap();
 
+        let mir_def_id = body.source.def_id().expect_local();
+
         // If the user explicitly annotated the input types, extract
         // those.
         //
         // e.g., `|x: FxHashMap<_, &'static u32>| ...`
         let user_provided_sig;
-        if !self.tcx().is_closure(self.mir_def_id.to_def_id()) {
+        if !self.tcx().is_closure(mir_def_id.to_def_id()) {
             user_provided_sig = None;
         } else {
-            let typeck_results = self.tcx().typeck(self.mir_def_id);
-            user_provided_sig =
-                match typeck_results.user_provided_sigs.get(&self.mir_def_id.to_def_id()) {
-                    None => None,
-                    Some(user_provided_poly_sig) => {
-                        // Instantiate the canonicalized variables from
-                        // user-provided signature (e.g., the `_` in the code
-                        // above) with fresh variables.
-                        let (poly_sig, _) =
-                            self.infcx.instantiate_canonical_with_fresh_inference_vars(
-                                body.span,
-                                &user_provided_poly_sig,
-                            );
+            let typeck_results = self.tcx().typeck(mir_def_id);
+            user_provided_sig = match typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id())
+            {
+                None => None,
+                Some(user_provided_poly_sig) => {
+                    // Instantiate the canonicalized variables from
+                    // user-provided signature (e.g., the `_` in the code
+                    // above) with fresh variables.
+                    let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
+                        body.span,
+                        &user_provided_poly_sig,
+                    );
 
-                        // Replace the bound items in the fn sig with fresh
-                        // variables, so that they represent the view from
-                        // "inside" the closure.
-                        Some(
-                            self.infcx
-                                .replace_bound_vars_with_fresh_vars(
-                                    body.span,
-                                    LateBoundRegionConversionTime::FnCall,
-                                    &poly_sig,
-                                )
-                                .0,
-                        )
-                    }
+                    // Replace the bound items in the fn sig with fresh
+                    // variables, so that they represent the view from
+                    // "inside" the closure.
+                    Some(
+                        self.infcx
+                            .replace_bound_vars_with_fresh_vars(
+                                body.span,
+                                LateBoundRegionConversionTime::FnCall,
+                                &poly_sig,
+                            )
+                            .0,
+                    )
                 }
+            }
         };
 
         debug!(
@@ -72,7 +73,7 @@
         );
 
         // Equate expected input tys with those in the MIR.
-        for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) {
+        for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
             // In MIR, argument N is stored in local N+1.
             let local = Local::new(argument_index + 1);
 
@@ -86,8 +87,8 @@
         }
 
         if let Some(user_provided_sig) = user_provided_sig {
-            for (&user_provided_input_ty, argument_index) in
-                user_provided_sig.inputs().iter().zip(0..)
+            for (argument_index, &user_provided_input_ty) in
+                user_provided_sig.inputs().iter().enumerate()
             {
                 // In MIR, closures begin an implicit `self`, so
                 // argument N is stored in local N+2.
@@ -122,7 +123,7 @@
         if let Err(terr) = self.eq_opaque_type_and_type(
             mir_output_ty,
             normalized_output_ty,
-            self.mir_def_id,
+            mir_def_id,
             Locations::All(output_span),
             ConstraintCategory::BoringNoLocation,
         ) {
@@ -145,7 +146,7 @@
             if let Err(err) = self.eq_opaque_type_and_type(
                 mir_output_ty,
                 user_provided_output_ty,
-                self.mir_def_id,
+                mir_def_id,
                 Locations::All(output_span),
                 ConstraintCategory::BoringNoLocation,
             ) {
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index 3ace146..4fc1c57 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -73,7 +73,7 @@
             $context.last_span,
             &format!(
                 "broken MIR in {:?} ({:?}): {}",
-                $context.mir_def_id,
+                $context.body.source.def_id(),
                 $elem,
                 format_args!($($message)*),
             ),
@@ -113,7 +113,6 @@
 /// - `param_env` -- parameter environment to use for trait solving
 /// - `body` -- MIR body to type-check
 /// - `promoted` -- map of promoted constants within `body`
-/// - `mir_def_id` -- `LocalDefId` from which the MIR is derived
 /// - `universal_regions` -- the universal regions from `body`s function signature
 /// - `location_table` -- MIR location map of `body`
 /// - `borrow_set` -- information about borrows occurring in `body`
@@ -126,7 +125,6 @@
     param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
     promoted: &IndexVec<Promoted, Body<'tcx>>,
-    mir_def_id: LocalDefId,
     universal_regions: &Rc<UniversalRegions<'tcx>>,
     location_table: &LocationTable,
     borrow_set: &BorrowSet<'tcx>,
@@ -170,7 +168,6 @@
 
     let opaque_type_values = type_check_internal(
         infcx,
-        mir_def_id,
         param_env,
         body,
         promoted,
@@ -192,7 +189,6 @@
 
 fn type_check_internal<'a, 'tcx, R>(
     infcx: &'a InferCtxt<'a, 'tcx>,
-    mir_def_id: LocalDefId,
     param_env: ty::ParamEnv<'tcx>,
     body: &'a Body<'tcx>,
     promoted: &'a IndexVec<Promoted, Body<'tcx>>,
@@ -205,7 +201,6 @@
     let mut checker = TypeChecker::new(
         infcx,
         body,
-        mir_def_id,
         param_env,
         region_bound_pairs,
         implicit_region_bound,
@@ -272,7 +267,6 @@
     body: &'b Body<'tcx>,
     promoted: &'b IndexVec<Promoted, Body<'tcx>>,
     last_span: Span,
-    mir_def_id: LocalDefId,
     errors_reported: bool,
 }
 
@@ -460,14 +454,7 @@
         body: &'b Body<'tcx>,
         promoted: &'b IndexVec<Promoted, Body<'tcx>>,
     ) -> Self {
-        TypeVerifier {
-            body,
-            promoted,
-            mir_def_id: cx.mir_def_id,
-            cx,
-            last_span: body.span,
-            errors_reported: false,
-        }
+        TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
     }
 
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -816,7 +803,6 @@
     /// User type annotations are shared between the main MIR and the MIR of
     /// all of the promoted items.
     user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
-    mir_def_id: LocalDefId,
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
@@ -965,7 +951,6 @@
     fn new(
         infcx: &'a InferCtxt<'a, 'tcx>,
         body: &'a Body<'tcx>,
-        mir_def_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
         implicit_region_bound: ty::Region<'tcx>,
@@ -975,7 +960,6 @@
         let mut checker = Self {
             infcx,
             last_span: DUMMY_SP,
-            mir_def_id,
             body,
             user_type_annotations: &body.user_type_annotations,
             param_env,
@@ -1145,7 +1129,7 @@
                 // the resulting inferend values are stored with the
                 // def-id of the base function.
                 let parent_def_id =
-                    self.tcx().closure_base_def_id(self.mir_def_id.to_def_id()).expect_local();
+                    self.tcx().closure_base_def_id(self.body.source.def_id()).expect_local();
                 return self.eq_opaque_type_and_type(sub, sup, parent_def_id, locations, category);
             } else {
                 return Err(terr);
@@ -1242,7 +1226,7 @@
         let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types;
         let mut opaque_type_values = Vec::new();
 
-        debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
+        debug!("eq_opaque_type_and_type: mir_def_id={:?}", body.source.def_id());
         let opaque_type_map = self.fully_perform_op(
             locations,
             category,
@@ -1793,7 +1777,7 @@
                 self.assert_iscleanup(body, block_data, target, is_cleanup)
             }
             TerminatorKind::SwitchInt { ref targets, .. } => {
-                for target in targets {
+                for target in targets.all_targets() {
                     self.assert_iscleanup(body, block_data, *target, is_cleanup);
                 }
             }
@@ -2001,12 +1985,7 @@
                         let span = body.source_info(location).span;
                         let ty = operand.ty(body, tcx);
                         if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
-                            let ccx = ConstCx::new_with_param_env(
-                                tcx,
-                                self.mir_def_id,
-                                body,
-                                self.param_env,
-                            );
+                            let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
                             // To determine if `const_in_array_repeat_expressions` feature gate should
                             // be mentioned, need to check if the rvalue is promotable.
                             let should_suggest =
@@ -2015,11 +1994,12 @@
                                 );
                             debug!("check_rvalue: should_suggest={:?}", should_suggest);
 
+                            let def_id = body.source.def_id().expect_local();
                             self.infcx.report_selection_error(
                                 &traits::Obligation::new(
                                     ObligationCause::new(
                                         span,
-                                        self.tcx().hir().local_def_id_to_hir_id(self.mir_def_id),
+                                        self.tcx().hir().local_def_id_to_hir_id(def_id),
                                         traits::ObligationCauseCode::RepeatVec(should_suggest),
                                     ),
                                     self.param_env,
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index a0ee7fd..6ef73b0 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -14,7 +14,7 @@
 use rustc_middle::ty::{self, subst::Subst, TyCtxt};
 use rustc_span::source_map::Span;
 use rustc_target::abi::{Abi, LayoutOf};
-use std::convert::TryInto;
+use std::convert::{TryFrom, TryInto};
 
 pub fn note_on_undefined_behavior_error() -> &'static str {
     "The rules on what exactly is undefined behavior aren't clear, \
@@ -148,10 +148,10 @@
         Scalar::Raw { data, .. } => {
             assert!(mplace.layout.is_zst());
             assert_eq!(
-                data,
-                mplace.layout.align.abi.bytes().into(),
-                "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what
-                 value this integer address must have",
+                u64::try_from(data).unwrap() % mplace.layout.align.abi.bytes(),
+                0,
+                "this MPlaceTy must come from a validated constant, thus we can assume the \
+                alignment is correct",
             );
             ConstValue::Scalar(Scalar::zst())
         }
@@ -343,7 +343,7 @@
                     // deny-by-default lint
                     _ => {
                         if let Some(p) = cid.promoted {
-                            let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span;
+                            let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span;
                             if let err_inval!(ReferencedConstant) = err.error {
                                 Err(err.report_as_error(
                                     tcx.at(span),
diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs
index 1db1f6c..aca822a 100644
--- a/compiler/rustc_mir/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs
@@ -151,17 +151,11 @@
         }
 }
 
-fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    is_const_fn(tcx, def_id)
-        && tcx.lookup_const_stability(def_id).map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
-}
-
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         is_const_fn_raw,
         is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()),
         is_promotable_const_fn,
-        const_fn_is_allowed_fn_ptr,
         ..*providers
     };
 }
diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs
index 978d2fe..4b235e1 100644
--- a/compiler/rustc_mir/src/const_eval/mod.rs
+++ b/compiler/rustc_mir/src/const_eval/mod.rs
@@ -50,7 +50,7 @@
     let (field_count, variant, down) = match val.ty.kind() {
         ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
         ty::Adt(def, _) if def.variants.is_empty() => {
-            return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) };
+            return mir::DestructuredConst { variant: None, fields: &[] };
         }
         ty::Adt(def, _) => {
             let variant = ecx.read_discriminant(op).unwrap().1;
diff --git a/compiler/rustc_mir/src/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs
index ca2bb6e..8a9ced9 100644
--- a/compiler/rustc_mir/src/dataflow/framework/direction.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs
@@ -1,5 +1,5 @@
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, BasicBlock, Location};
+use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets};
 use rustc_middle::ty::TyCtxt;
 use std::ops::RangeInclusive;
 
@@ -488,11 +488,10 @@
                 }
             }
 
-            SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => {
+            SwitchInt { ref targets, ref discr, switch_ty: _ } => {
                 let mut applier = SwitchIntEdgeEffectApplier {
                     exit_state,
-                    targets: targets.as_ref(),
-                    values: values.as_ref(),
+                    targets,
                     propagate,
                     effects_applied: false,
                 };
@@ -504,8 +503,8 @@
                 } = applier;
 
                 if !effects_applied {
-                    for &target in targets.iter() {
-                        propagate(target, exit_state);
+                    for target in targets.all_targets() {
+                        propagate(*target, exit_state);
                     }
                 }
             }
@@ -515,8 +514,7 @@
 
 struct SwitchIntEdgeEffectApplier<'a, D, F> {
     exit_state: &'a mut D,
-    values: &'a [u128],
-    targets: &'a [BasicBlock],
+    targets: &'a SwitchTargets,
     propagate: F,
 
     effects_applied: bool,
@@ -531,7 +529,7 @@
         assert!(!self.effects_applied);
 
         let mut tmp = None;
-        for (&value, &target) in self.values.iter().zip(self.targets.iter()) {
+        for (value, target) in self.targets.iter() {
             let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
             apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target });
             (self.propagate)(target, tmp);
@@ -539,7 +537,7 @@
 
         // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`,
         // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state.
-        let otherwise = self.targets.last().copied().unwrap();
+        let otherwise = self.targets.otherwise();
         apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise });
         (self.propagate)(otherwise, self.exit_state);
 
diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs
index f39c78f..1b7264f 100644
--- a/compiler/rustc_mir/src/dataflow/framework/engine.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs
@@ -2,7 +2,6 @@
 
 use std::borrow::BorrowMut;
 use std::ffi::OsString;
-use std::fs;
 use std::path::PathBuf;
 
 use rustc_ast as ast;
@@ -12,7 +11,7 @@
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::{self, traversal, BasicBlock};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
 
 use super::fmt::DebugWithContext;
@@ -21,7 +20,7 @@
     visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
     ResultsCursor, ResultsVisitor,
 };
-use crate::util::pretty::dump_enabled;
+use crate::util::pretty::{create_dump_file, dump_enabled};
 
 /// A dataflow analysis that has converged to fixpoint.
 pub struct Results<'tcx, A>
@@ -63,15 +62,6 @@
         let blocks = mir::traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
     }
-
-    pub fn visit_in_rpo_with(
-        &self,
-        body: &'mir mir::Body<'tcx>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
-    ) {
-        let blocks = mir::traversal::reverse_postorder(body);
-        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
-    }
 }
 
 /// A solver for dataflow problems.
@@ -81,7 +71,6 @@
 {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
-    def_id: DefId,
     dead_unwinds: Option<&'a BitSet<BasicBlock>>,
     entry_sets: IndexVec<BasicBlock, A::Domain>,
     pass_name: Option<&'static str>,
@@ -103,18 +92,13 @@
     T: Idx,
 {
     /// Creates a new `Engine` to solve a gen-kill dataflow problem.
-    pub fn new_gen_kill(
-        tcx: TyCtxt<'tcx>,
-        body: &'a mir::Body<'tcx>,
-        def_id: DefId,
-        analysis: A,
-    ) -> Self {
+    pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
         // If there are no back-edges in the control-flow graph, we only ever need to apply the
         // transfer function for each block exactly once (assuming that we process blocks in RPO).
         //
         // In this case, there's no need to compute the block transfer functions ahead of time.
         if !body.is_cfg_cyclic() {
-            return Self::new(tcx, body, def_id, analysis, None);
+            return Self::new(tcx, body, analysis, None);
         }
 
         // Otherwise, compute and store the cumulative transfer function for each block.
@@ -131,7 +115,7 @@
             trans_for_block[bb].apply(state.borrow_mut());
         });
 
-        Self::new(tcx, body, def_id, analysis, Some(apply_trans as Box<_>))
+        Self::new(tcx, body, analysis, Some(apply_trans as Box<_>))
     }
 }
 
@@ -145,19 +129,13 @@
     ///
     /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for
     /// better performance.
-    pub fn new_generic(
-        tcx: TyCtxt<'tcx>,
-        body: &'a mir::Body<'tcx>,
-        def_id: DefId,
-        analysis: A,
-    ) -> Self {
-        Self::new(tcx, body, def_id, analysis, None)
+    pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
+        Self::new(tcx, body, analysis, None)
     }
 
     fn new(
         tcx: TyCtxt<'tcx>,
         body: &'a mir::Body<'tcx>,
-        def_id: DefId,
         analysis: A,
         apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
     ) -> Self {
@@ -173,7 +151,6 @@
             analysis,
             tcx,
             body,
-            def_id,
             dead_unwinds: None,
             pass_name: None,
             entry_sets,
@@ -209,7 +186,6 @@
             analysis,
             body,
             dead_unwinds,
-            def_id,
             mut entry_sets,
             tcx,
             apply_trans_for_block,
@@ -261,9 +237,9 @@
 
         let results = Results { analysis, entry_sets };
 
-        let res = write_graphviz_results(tcx, def_id, &body, &results, pass_name);
+        let res = write_graphviz_results(tcx, &body, &results, pass_name);
         if let Err(e) = res {
-            warn!("Failed to write graphviz dataflow results: {}", e);
+            error!("Failed to write graphviz dataflow results: {}", e);
         }
 
         results
@@ -276,7 +252,6 @@
 /// `rustc_mir` attributes.
 fn write_graphviz_results<A>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
     body: &mir::Body<'tcx>,
     results: &Results<'tcx, A>,
     pass_name: Option<&'static str>,
@@ -285,6 +260,10 @@
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
 {
+    use std::fs;
+    use std::io::{self, Write};
+
+    let def_id = body.source.def_id();
     let attrs = match RustcMirAttrs::parse(tcx, def_id) {
         Ok(attrs) => attrs,
 
@@ -292,27 +271,29 @@
         Err(()) => return Ok(()),
     };
 
-    let path = match attrs.output_path(A::NAME) {
-        Some(path) => path,
+    let mut file = match attrs.output_path(A::NAME) {
+        Some(path) => {
+            debug!("printing dataflow results for {:?} to {}", def_id, path.display());
+            if let Some(parent) = path.parent() {
+                fs::create_dir_all(parent)?;
+            }
+            io::BufWriter::new(fs::File::create(&path)?)
+        }
 
         None if tcx.sess.opts.debugging_opts.dump_mir_dataflow
             && dump_enabled(tcx, A::NAME, def_id) =>
         {
-            // FIXME: Use some variant of `pretty::dump_path` for this
-            let mut path = PathBuf::from(&tcx.sess.opts.debugging_opts.dump_mir_dir);
-
-            let crate_name = tcx.crate_name(def_id.krate);
-            let item_name = ty::print::with_forced_impl_filename_line(|| {
-                tcx.def_path(def_id).to_filename_friendly_no_crate()
-            });
-
-            let pass_name = pass_name.map(|s| format!(".{}", s)).unwrap_or_default();
-
-            path.push(format!("{}.{}.{}{}.dot", crate_name, item_name, A::NAME, pass_name));
-            path
+            create_dump_file(
+                tcx,
+                ".dot",
+                None,
+                A::NAME,
+                &pass_name.unwrap_or("-----"),
+                body.source,
+            )?
         }
 
-        None => return Ok(()),
+        _ => return Ok(()),
     };
 
     let style = match attrs.formatter {
@@ -320,10 +301,9 @@
         _ => graphviz::OutputStyle::AfterOnly,
     };
 
-    debug!("printing dataflow results for {:?} to {}", def_id, path.display());
     let mut buf = Vec::new();
 
-    let graphviz = graphviz::Formatter::new(body, def_id, results, style);
+    let graphviz = graphviz::Formatter::new(body, results, style);
     let mut render_opts =
         vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())];
     if tcx.sess.opts.debugging_opts.graphviz_dark_mode {
@@ -331,10 +311,7 @@
     }
     dot::render_opts(&graphviz, &mut buf, &render_opts)?;
 
-    if let Some(parent) = path.parent() {
-        fs::create_dir_all(parent)?;
-    }
-    fs::write(&path, buf)?;
+    file.write_all(&buf)?;
 
     Ok(())
 }
diff --git a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs
index 5d4c425..4e54257 100644
--- a/compiler/rustc_mir/src/dataflow/framework/graphviz.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs
@@ -6,7 +6,6 @@
 
 use regex::Regex;
 use rustc_graphviz as dot;
-use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{self, BasicBlock, Body, Location};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
@@ -33,7 +32,6 @@
     A: Analysis<'tcx>,
 {
     body: &'a Body<'tcx>,
-    def_id: DefId,
     results: &'a Results<'tcx, A>,
     style: OutputStyle,
 }
@@ -42,13 +40,8 @@
 where
     A: Analysis<'tcx>,
 {
-    pub fn new(
-        body: &'a Body<'tcx>,
-        def_id: DefId,
-        results: &'a Results<'tcx, A>,
-        style: OutputStyle,
-    ) -> Self {
-        Formatter { body, def_id, results, style }
+    pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self {
+        Formatter { body, results, style }
     }
 }
 
@@ -77,7 +70,7 @@
     type Edge = CfgEdge;
 
     fn graph_id(&self) -> dot::Id<'_> {
-        let name = graphviz_safe_def_name(self.def_id);
+        let name = graphviz_safe_def_name(self.body.source.def_id());
         dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
     }
 
diff --git a/compiler/rustc_mir/src/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs
index 65c159e..524ad0a 100644
--- a/compiler/rustc_mir/src/dataflow/framework/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs
@@ -13,9 +13,9 @@
 //! ```ignore(cross-crate-imports)
 //! use rustc_mir::dataflow::Analysis; // Makes `into_engine` available.
 //!
-//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, did: DefId) {
+//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
 //!     let analysis = MyAnalysis::new()
-//!         .into_engine(tcx, body, did)
+//!         .into_engine(tcx, body)
 //!         .iterate_to_fixpoint()
 //!         .into_results_cursor(body);
 //!
@@ -33,7 +33,6 @@
 use std::borrow::BorrowMut;
 use std::cmp::Ordering;
 
-use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::{BitSet, HybridBitSet};
 use rustc_index::vec::Idx;
 use rustc_middle::mir::{self, BasicBlock, Location};
@@ -218,16 +217,11 @@
     ///     .iterate_to_fixpoint()
     ///     .into_results_cursor(body);
     /// ```
-    fn into_engine(
-        self,
-        tcx: TyCtxt<'tcx>,
-        body: &'mir mir::Body<'tcx>,
-        def_id: DefId,
-    ) -> Engine<'mir, 'tcx, Self>
+    fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self>
     where
         Self: Sized,
     {
-        Engine::new_generic(tcx, body, def_id, self)
+        Engine::new_generic(tcx, body, self)
     }
 }
 
@@ -381,16 +375,11 @@
 
     /* Extension methods */
 
-    fn into_engine(
-        self,
-        tcx: TyCtxt<'tcx>,
-        body: &'mir mir::Body<'tcx>,
-        def_id: DefId,
-    ) -> Engine<'mir, 'tcx, Self>
+    fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self>
     where
         Self: Sized,
     {
-        Engine::new_gen_kill(tcx, body, def_id, self)
+        Engine::new_gen_kill(tcx, body, self)
     }
 }
 
diff --git a/compiler/rustc_mir/src/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs
index d4b9600..185f0ed 100644
--- a/compiler/rustc_mir/src/dataflow/impls/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/mod.rs
@@ -358,6 +358,10 @@
         discr: &mir::Operand<'tcx>,
         edge_effects: &mut impl SwitchIntEdgeEffects<G>,
     ) {
+        if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+            return;
+        }
+
         let enum_ = discr.place().and_then(|discr| {
             switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr)
         });
@@ -469,6 +473,10 @@
         discr: &mir::Operand<'tcx>,
         edge_effects: &mut impl SwitchIntEdgeEffects<G>,
     ) {
+        if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+            return;
+        }
+
         if !self.mark_inactive_variants_as_uninit {
             return;
         }
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
index 5c3e353..ab7fada 100644
--- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
+++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
@@ -362,17 +362,18 @@
     fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
         match term.kind {
             TerminatorKind::Goto { target: _ }
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::FalseUnwind { .. }
+            // In some sense returning moves the return place into the current
+            // call's destination, however, since there are no statements after
+            // this that could possibly access the return place, this doesn't
+            // need recording.
+            | TerminatorKind::Return
             | TerminatorKind::Resume
             | TerminatorKind::Abort
             | TerminatorKind::GeneratorDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::Unreachable => {}
 
-            TerminatorKind::Return => {
-                self.gather_move(Place::return_place());
-            }
-
             TerminatorKind::Assert { ref cond, .. } => {
                 self.gather_operand(cond);
             }
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs
index 0e16b0c..affeae5 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_mir/src/interpret/cast.rs
@@ -139,9 +139,14 @@
 
         // # First handle non-scalar source values.
 
-        // Handle cast from a univariant (ZST) enum.
+        // Handle cast from a ZST enum (0 or 1 variants).
         match src.layout.variants {
             Variants::Single { index } => {
+                if src.layout.abi.is_uninhabited() {
+                    // This is dead code, because an uninhabited enum is UB to
+                    // instantiate.
+                    throw_ub!(Unreachable);
+                }
                 if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
                     assert!(src.layout.is_zst());
                     let discr_layout = self.layout_of(discr.ty)?;
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index f970969..ec1195d 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -48,8 +48,41 @@
         FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer<M::PointerTag>>,
 }
 
+// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
+// boundary and dropped in the other thread, it would exit the span in the other thread.
+struct SpanGuard(tracing::Span, std::marker::PhantomData<*const u8>);
+
+impl SpanGuard {
+    /// By default a `SpanGuard` does nothing.
+    fn new() -> Self {
+        Self(tracing::Span::none(), std::marker::PhantomData)
+    }
+
+    /// If a span is entered, we exit the previous span (if any, normally none) and enter the
+    /// new span. This is mainly so we don't have to use `Option` for the `tracing_span` field of
+    /// `Frame` by creating a dummy span to being with and then entering it once the frame has
+    /// been pushed.
+    fn enter(&mut self, span: tracing::Span) {
+        // This executes the destructor on the previous instance of `SpanGuard`, ensuring that
+        // we never enter or exit more spans than vice versa. Unless you `mem::leak`, then we
+        // can't protect the tracing stack, but that'll just lead to weird logging, no actual
+        // problems.
+        *self = Self(span, std::marker::PhantomData);
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.enter(id);
+        });
+    }
+}
+
+impl Drop for SpanGuard {
+    fn drop(&mut self) {
+        self.0.with_subscriber(|(id, dispatch)| {
+            dispatch.exit(id);
+        });
+    }
+}
+
 /// A stack frame.
-#[derive(Clone)]
 pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> {
     ////////////////////////////////////////////////////////////////////////////////
     // Function and callsite information
@@ -80,6 +113,11 @@
     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
     pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
 
+    /// The span of the `tracing` crate is stored here.
+    /// When the guard is dropped, the span is exited. This gives us
+    /// a full stack trace on all tracing statements.
+    tracing_span: SpanGuard,
+
     ////////////////////////////////////////////////////////////////////////////////
     // Current position within the function
     ////////////////////////////////////////////////////////////////////////////////
@@ -184,6 +222,7 @@
             locals: self.locals,
             loc: self.loc,
             extra,
+            tracing_span: self.tracing_span,
         }
     }
 }
@@ -438,16 +477,12 @@
         }
         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
         if let Some(promoted) = promoted {
-            return Ok(&self.tcx.promoted_mir_of_opt_const_arg(def)[promoted]);
+            return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
         }
         match instance {
             ty::InstanceDef::Item(def) => {
                 if self.tcx.is_mir_available(def.did) {
-                    if let Some((did, param_did)) = def.as_const_arg() {
-                        Ok(self.tcx.optimized_mir_of_const_arg((did, param_did)))
-                    } else {
-                        Ok(self.tcx.optimized_mir(def.did))
-                    }
+                    Ok(self.tcx.optimized_mir_opt_const_arg(def))
                 } else {
                     throw_unsup!(NoMirFor(def.did))
                 }
@@ -637,11 +672,6 @@
         return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
-        if !self.stack().is_empty() {
-            info!("PAUSING({}) {}", self.frame_idx(), self.frame().instance);
-        }
-        ::log_settings::settings().indentation += 1;
-
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
@@ -652,6 +682,7 @@
             // all methods actually know about the frame
             locals: IndexVec::new(),
             instance,
+            tracing_span: SpanGuard::new(),
             extra: (),
         };
         let frame = M::init_frame_extra(self, pre_frame)?;
@@ -696,7 +727,9 @@
         self.frame_mut().locals = locals;
         M::after_stack_push(self)?;
         self.frame_mut().loc = Ok(mir::Location::START);
-        info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance);
+
+        let span = info_span!("frame", "{}", instance);
+        self.frame_mut().tracing_span.enter(span);
 
         Ok(())
     }
@@ -747,10 +780,8 @@
     /// cause us to continue unwinding.
     pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx> {
         info!(
-            "LEAVING({}) {} (unwinding = {})",
-            self.frame_idx(),
-            self.frame().instance,
-            unwinding
+            "popping stack frame ({})",
+            if unwinding { "during unwinding" } else { "returning from function" }
         );
 
         // Sanity check `unwinding`.
@@ -766,7 +797,6 @@
             throw_ub_format!("unwinding past the topmost frame of the stack");
         }
 
-        ::log_settings::settings().indentation -= 1;
         let frame =
             self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
 
@@ -823,15 +853,6 @@
             }
         }
 
-        if !self.stack().is_empty() {
-            info!(
-                "CONTINUING({}) {} (unwinding = {})",
-                self.frame_idx(),
-                self.frame().instance,
-                unwinding
-            );
-        }
-
         Ok(())
     }
 
@@ -995,7 +1016,16 @@
 {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) {
         // Exhaustive match on fields to make sure we forget no field.
-        let Frame { body, instance, return_to_block, return_place, locals, loc, extra } = self;
+        let Frame {
+            body,
+            instance,
+            return_to_block,
+            return_place,
+            locals,
+            loc,
+            extra,
+            tracing_span: _,
+        } = self;
         body.hash_stable(hcx, hasher);
         instance.hash_stable(hcx, hasher);
         return_to_block.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs
index dd5e9c9..945791e 100644
--- a/compiler/rustc_mir/src/interpret/intern.rs
+++ b/compiler/rustc_mir/src/interpret/intern.rs
@@ -187,6 +187,12 @@
                 return walked;
             }
         }
+
+        // ZSTs do not need validation unless they're uninhabited
+        if mplace.layout.is_zst() && !mplace.layout.abi.is_uninhabited() {
+            return Ok(());
+        }
+
         self.walk_aggregate(mplace, fields)
     }
 
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index 3718da1..66dbacb 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -3,6 +3,7 @@
 //! interpreting common C functions leak into CTFE.
 
 use std::borrow::{Borrow, Cow};
+use std::fmt::Debug;
 use std::hash::Hash;
 
 use rustc_middle::mir;
@@ -79,19 +80,19 @@
 /// and some use case dependent behaviour can instead be applied.
 pub trait Machine<'mir, 'tcx>: Sized {
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
-    type MemoryKind: ::std::fmt::Debug + ::std::fmt::Display + MayLeak + Eq + 'static;
+    type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static;
 
     /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
     /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
     /// The `default()` is used for pointers to consts, statics, vtables and functions.
     /// The `Debug` formatting is used for displaying pointers; we cannot use `Display`
     /// as `()` does not implement that, but it should be "nice" output.
-    type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;
+    type PointerTag: Debug + Copy + Eq + Hash + 'static;
 
     /// Machines can define extra (non-instance) things that represent values of function pointers.
     /// For example, Miri uses this to return a function pointer from `dlsym`
     /// that can later be called to execute the right thing.
-    type ExtraFnVal: ::std::fmt::Debug + Copy;
+    type ExtraFnVal: Debug + Copy;
 
     /// Extra data stored in every call frame.
     type FrameExtra;
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index 735f890..3c68b1c 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -117,7 +117,7 @@
         ty::tls::with(|tcx| {
             match self.imm {
                 Immediate::Scalar(s) => {
-                    if let Some(ty) = tcx.lift(&self.layout.ty) {
+                    if let Some(ty) = tcx.lift(self.layout.ty) {
                         let cx = FmtPrinter::new(tcx, f, Namespace::ValueNS);
                         p(cx, s, ty)?;
                         return Ok(());
@@ -133,7 +133,7 @@
     }
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for ImmTy<'tcx, Tag> {
     type Target = Immediate<Tag>;
     #[inline(always)]
     fn deref(&self) -> &Immediate<Tag> {
@@ -156,7 +156,7 @@
     pub layout: TyAndLayout<'tcx>,
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for OpTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for OpTy<'tcx, Tag> {
     type Target = Operand<Tag>;
     #[inline(always)]
     fn deref(&self) -> &Operand<Tag> {
@@ -340,7 +340,7 @@
     pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
         let len = mplace.len(self)?;
         let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?;
-        let str = ::std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
+        let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
         Ok(str)
     }
 
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index 72551b2..fe25f8c 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -3,6 +3,7 @@
 //! All high-level functions to write to memory work on places as destinations.
 
 use std::convert::TryFrom;
+use std::fmt::Debug;
 use std::hash::Hash;
 
 use rustc_macros::HashStable;
@@ -86,7 +87,7 @@
     pub layout: TyAndLayout<'tcx>,
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for PlaceTy<'tcx, Tag> {
     type Target = Place<Tag>;
     #[inline(always)]
     fn deref(&self) -> &Place<Tag> {
@@ -101,7 +102,7 @@
     pub layout: TyAndLayout<'tcx>,
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for MPlaceTy<'tcx, Tag> {
     type Target = MemPlace<Tag>;
     #[inline(always)]
     fn deref(&self) -> &MemPlace<Tag> {
@@ -226,7 +227,7 @@
 }
 
 // These are defined here because they produce a place.
-impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
+impl<'tcx, Tag: Debug + Copy> OpTy<'tcx, Tag> {
     #[inline(always)]
     /// Note: do not call `as_ref` on the resulting place. This function should only be used to
     /// read from the resulting mplace, not to get its address back.
@@ -251,7 +252,7 @@
     }
 }
 
-impl<Tag: ::std::fmt::Debug> Place<Tag> {
+impl<Tag: Debug> Place<Tag> {
     #[inline]
     pub fn assert_mem_place(self) -> MemPlace<Tag> {
         match self {
@@ -261,7 +262,7 @@
     }
 }
 
-impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
+impl<'tcx, Tag: Debug> PlaceTy<'tcx, Tag> {
     #[inline]
     pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
         MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout }
@@ -272,7 +273,7 @@
 impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M>
 where
     // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
-    Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static,
+    Tag: Debug + Copy + Eq + Hash + 'static,
     M: Machine<'mir, 'tcx, PointerTag = Tag>,
     // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
     M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>,
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index 9f200ca..bb11c2a 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -24,16 +24,16 @@
 
             Goto { target } => self.go_to_block(target),
 
-            SwitchInt { ref discr, ref values, ref targets, switch_ty } => {
+            SwitchInt { ref discr, ref targets, switch_ty } => {
                 let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
                 trace!("SwitchInt({:?})", *discr);
                 assert_eq!(discr.layout.ty, switch_ty);
 
                 // Branch to the `otherwise` case by default, if no match is found.
-                assert!(!targets.is_empty());
-                let mut target_block = targets[targets.len() - 1];
+                assert!(!targets.iter().is_empty());
+                let mut target_block = targets.otherwise();
 
-                for (index, &const_int) in values.iter().enumerate() {
+                for (const_int, target) in targets.iter() {
                     // Compare using binary_op, to also support pointer values
                     let res = self
                         .overflowing_binary_op(
@@ -43,7 +43,7 @@
                         )?
                         .0;
                     if res.to_bool()? {
-                        target_block = targets[index];
+                        target_block = target;
                         break;
                     }
                 }
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 7e12cc9..4171765 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -197,6 +197,7 @@
 use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
 use smallvec::SmallVec;
 use std::iter;
+use std::ops::Range;
 use std::path::PathBuf;
 
 #[derive(PartialEq)]
@@ -210,9 +211,8 @@
 pub struct InliningMap<'tcx> {
     // Maps a source mono item to the range of mono items
     // accessed by it.
-    // The two numbers in the tuple are the start (inclusive) and
-    // end index (exclusive) within the `targets` vecs.
-    index: FxHashMap<MonoItem<'tcx>, (usize, usize)>,
+    // The range selects elements within the `targets` vecs.
+    index: FxHashMap<MonoItem<'tcx>, Range<usize>>,
     targets: Vec<MonoItem<'tcx>>,
 
     // Contains one bit per mono item in the `targets` field. That bit
@@ -245,7 +245,7 @@
         }
 
         let end_index = self.targets.len();
-        assert!(self.index.insert(source, (start_index, end_index)).is_none());
+        assert!(self.index.insert(source, start_index..end_index).is_none());
     }
 
     // Internally iterate over all items referenced by `source` which will be
@@ -254,9 +254,9 @@
     where
         F: FnMut(MonoItem<'tcx>),
     {
-        if let Some(&(start_index, end_index)) = self.index.get(&source) {
-            for (i, candidate) in self.targets[start_index..end_index].iter().enumerate() {
-                if self.inlines.contains(start_index + i) {
+        if let Some(range) = self.index.get(&source) {
+            for (i, candidate) in self.targets[range.clone()].iter().enumerate() {
+                if self.inlines.contains(range.start + i) {
                     f(*candidate);
                 }
             }
@@ -268,8 +268,8 @@
     where
         F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]),
     {
-        for (&accessor, &(start_index, end_index)) in &self.index {
-            f(accessor, &self.targets[start_index..end_index])
+        for (&accessor, range) in &self.index {
+            f(accessor, &self.targets[range.clone()])
         }
     }
 }
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
index 3c89111..5083a45 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
@@ -532,7 +532,7 @@
 }
 
 fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility {
-    if !tcx.sess.target.target.options.default_hidden_visibility {
+    if !tcx.sess.target.options.default_hidden_visibility {
         return Visibility::Default;
     }
 
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
index 7e4d189..5431d22 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir/src/shim.rs
@@ -78,8 +78,6 @@
     run_passes(
         tcx,
         &mut result,
-        instance,
-        None,
         MirPhase::Const,
         &[&[
             &add_moves_for_packed_drops::AddMovesForPackedDrops,
@@ -163,7 +161,9 @@
     block(&mut blocks, TerminatorKind::Goto { target: return_block });
     block(&mut blocks, TerminatorKind::Return);
 
-    let mut body = new_body(blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
+    let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty));
+    let mut body =
+        new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
 
     if let Some(..) = ty {
         // The first argument (index 0), but add 1 for the return value.
@@ -202,12 +202,14 @@
 }
 
 fn new_body<'tcx>(
+    source: MirSource<'tcx>,
     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
     arg_count: usize,
     span: Span,
 ) -> Body<'tcx> {
     Body::new(
+        source,
         basic_blocks,
         IndexVec::from_elem_n(
             SourceScopeData { span, parent_scope: None, local_data: ClearCrossCrate::Clear },
@@ -344,7 +346,11 @@
     }
 
     fn into_mir(self) -> Body<'tcx> {
-        new_body(self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
+        let source = MirSource::from_instance(ty::InstanceDef::CloneShim(
+            self.def_id,
+            self.sig.inputs_and_output[0],
+        ));
+        new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
     }
 
     fn source_info(&self) -> SourceInfo {
@@ -834,7 +840,8 @@
         block(&mut blocks, vec![], TerminatorKind::Resume, true);
     }
 
-    let mut body = new_body(blocks, local_decls, sig.inputs().len(), span);
+    let mut body =
+        new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
 
     if let Abi::RustCall = sig.abi {
         body.spread_arg = Some(Local::new(sig.inputs().len()));
@@ -897,18 +904,16 @@
         is_cleanup: false,
     };
 
-    let body =
-        new_body(IndexVec::from_elem_n(start_block, 1), local_decls, sig.inputs().len(), span);
-
-    crate::util::dump_mir(
-        tcx,
-        None,
-        "mir_map",
-        &0,
-        crate::transform::MirSource::item(ctor_id),
-        &body,
-        |_, _| Ok(()),
+    let source = MirSource::item(ctor_id);
+    let body = new_body(
+        source,
+        IndexVec::from_elem_n(start_block, 1),
+        local_decls,
+        sig.inputs().len(),
+        span,
     );
 
+    crate::util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
+
     body
 }
diff --git a/compiler/rustc_mir/src/transform/add_call_guards.rs b/compiler/rustc_mir/src/transform/add_call_guards.rs
index 3385911..1dddaeb 100644
--- a/compiler/rustc_mir/src/transform/add_call_guards.rs
+++ b/compiler/rustc_mir/src/transform/add_call_guards.rs
@@ -1,4 +1,4 @@
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -31,7 +31,7 @@
  */
 
 impl<'tcx> MirPass<'tcx> for AddCallGuards {
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         self.add_call_guards(body);
     }
 }
diff --git a/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs b/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
index a02d0f6..417e0a5 100644
--- a/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
@@ -1,8 +1,7 @@
-use rustc_hir::def_id::DefId;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util;
 use crate::util::patch::MirPatch;
 
@@ -40,22 +39,19 @@
 pub struct AddMovesForPackedDrops;
 
 impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        debug!("add_moves_for_packed_drops({:?} @ {:?})", src, body.span);
-        add_moves_for_packed_drops(tcx, body, src.def_id());
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
+        add_moves_for_packed_drops(tcx, body);
     }
 }
 
-pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, def_id: DefId) {
-    let patch = add_moves_for_packed_drops_patch(tcx, body, def_id);
+pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let patch = add_moves_for_packed_drops_patch(tcx, body);
     patch.apply(body);
 }
 
-fn add_moves_for_packed_drops_patch<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    def_id: DefId,
-) -> MirPatch<'tcx> {
+fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> MirPatch<'tcx> {
+    let def_id = body.source.def_id();
     let mut patch = MirPatch::new(body);
     let param_env = tcx.param_env(def_id);
 
diff --git a/compiler/rustc_mir/src/transform/add_retag.rs b/compiler/rustc_mir/src/transform/add_retag.rs
index 0c596ba..eec704e 100644
--- a/compiler/rustc_mir/src/transform/add_retag.rs
+++ b/compiler/rustc_mir/src/transform/add_retag.rs
@@ -4,7 +4,7 @@
 //! of MIR building, and only after this pass we think of the program has having the
 //! normal MIR semantics.
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -58,13 +58,13 @@
 }
 
 impl<'tcx> MirPass<'tcx> for AddRetag {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if !tcx.sess.opts.debugging_opts.mir_emit_retag {
             return;
         }
 
         // We need an `AllCallEdges` pass before we can do any work.
-        super::add_call_guards::AllCallEdges.run_pass(tcx, src, body);
+        super::add_call_guards::AllCallEdges.run_pass(tcx, body);
 
         let (span, arg_count) = (body.span, body.arg_count);
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
index 70c1aed..fb89b36 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -6,12 +6,12 @@
 use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
 use rustc_span::def_id::DefId;
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 
 pub struct CheckConstItemMutation;
 
 impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut checker = ConstMutationChecker { body, tcx, target_local: None };
         checker.visit_body(&body);
     }
@@ -31,6 +31,34 @@
             None
         }
     }
+
+    fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
+        let def_id = self.is_const_item(local)?;
+
+        // We avoid linting mutation of a const item if the const's type has a
+        // Drop impl. The Drop logic observes the mutation which was performed.
+        //
+        //     pub struct Log { msg: &'static str }
+        //     pub const LOG: Log = Log { msg: "" };
+        //     impl Drop for Log {
+        //         fn drop(&mut self) { println!("{}", self.msg); }
+        //     }
+        //
+        //     LOG.msg = "wow";  // prints "wow"
+        //
+        // FIXME(https://github.com/rust-lang/rust/issues/77425):
+        // Drop this exception once there is a stable attribute to suppress the
+        // const item mutation lint for a single specific const only. Something
+        // equivalent to:
+        //
+        //     #[const_mutation_allowed]
+        //     pub const LOG: Log = Log { msg: "" };
+        match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) {
+            Some(_) => None,
+            None => Some(def_id),
+        }
+    }
+
     fn lint_const_item_usage(
         &self,
         const_item: DefId,
@@ -59,12 +87,16 @@
             // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
             // so emitting a lint would be redundant.
             if !lhs.projection.is_empty() {
-                if let Some(def_id) = self.is_const_item(lhs.local) {
-                    self.lint_const_item_usage(def_id, loc, |lint| {
-                        let mut lint = lint.build("attempting to modify a `const` item");
-                        lint.note("each usage of a `const` item creates a new temporary - the original `const` item will not be modified");
-                        lint
-                    })
+                if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
+                    // Don't lint on writes through a pointer
+                    // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`)
+                    if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) {
+                        self.lint_const_item_usage(def_id, loc, |lint| {
+                            let mut lint = lint.build("attempting to modify a `const` item");
+                            lint.note("each usage of a `const` item creates a new temporary - the original `const` item will not be modified");
+                            lint
+                        })
+                    }
                 }
             }
             // We are looking for MIR of the form:
diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs
index 8d4efd8..33815ce 100644
--- a/compiler/rustc_mir/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs
@@ -24,25 +24,28 @@
 pub struct ConstCx<'mir, 'tcx> {
     pub body: &'mir mir::Body<'tcx>,
     pub tcx: TyCtxt<'tcx>,
-    pub def_id: LocalDefId,
     pub param_env: ty::ParamEnv<'tcx>,
     pub const_kind: Option<hir::ConstContext>,
 }
 
 impl ConstCx<'mir, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'mir mir::Body<'tcx>) -> Self {
+    pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
+        let def_id = body.source.def_id().expect_local();
         let param_env = tcx.param_env(def_id);
-        Self::new_with_param_env(tcx, def_id, body, param_env)
+        Self::new_with_param_env(tcx, body, param_env)
     }
 
     pub fn new_with_param_env(
         tcx: TyCtxt<'tcx>,
-        def_id: LocalDefId,
         body: &'mir mir::Body<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Self {
-        let const_kind = tcx.hir().body_const_context(def_id);
-        ConstCx { body, tcx, def_id: def_id, param_env, const_kind }
+        let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local());
+        ConstCx { body, tcx, param_env, const_kind }
+    }
+
+    pub fn def_id(&self) -> LocalDefId {
+        self.body.source.def_id().expect_local()
     }
 
     /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
@@ -55,7 +58,17 @@
     pub fn is_const_stable_const_fn(&self) -> bool {
         self.const_kind == Some(hir::ConstContext::ConstFn)
             && self.tcx.features().staged_api
-            && is_const_stable_const_fn(self.tcx, self.def_id.to_def_id())
+            && is_const_stable_const_fn(self.tcx, self.def_id().to_def_id())
+    }
+
+    /// Returns the function signature of the item being const-checked if it is a `fn` or `const fn`.
+    pub fn fn_sig(&self) -> Option<&'tcx hir::FnSig<'tcx>> {
+        // Get this from the HIR map instead of a query to avoid cycle errors.
+        //
+        // FIXME: Is this still an issue?
+        let hir_map = self.tcx.hir();
+        let hir_id = hir_map.local_def_id_to_hir_id(self.def_id());
+        hir_map.fn_sig_by_hir_id(hir_id)
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 1d74108..bd51136 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -1,8 +1,9 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_middle::mir;
 use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
@@ -10,49 +11,6 @@
 
 use super::ConstCx;
 
-/// Emits an error and returns `true` if `op` is not allowed in the given const context.
-pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) -> bool {
-    debug!("illegal_op: op={:?}", op);
-
-    let gate = match op.status_in_item(ccx) {
-        Status::Allowed => return false,
-
-        Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
-            let unstable_in_stable = ccx.is_const_stable_const_fn()
-                && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);
-
-            if unstable_in_stable {
-                ccx.tcx.sess
-                    .struct_span_err(
-                        span,
-                        &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
-                    )
-                    .span_suggestion(
-                        ccx.body.span,
-                        "if it is not part of the public API, make this function unstably const",
-                        concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
-                        Applicability::HasPlaceholders,
-                    )
-                    .note("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
-                    .emit();
-            }
-
-            return unstable_in_stable;
-        }
-
-        Status::Unstable(gate) => Some(gate),
-        Status::Forbidden => None,
-    };
-
-    if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
-        ccx.tcx.sess.miri_unleashed_feature(span, gate);
-        return false;
-    }
-
-    op.emit_error(ccx, span);
-    true
-}
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Status {
     Allowed,
@@ -60,63 +18,32 @@
     Forbidden,
 }
 
+#[derive(Clone, Copy)]
+pub enum DiagnosticImportance {
+    /// An operation that must be removed for const-checking to pass.
+    Primary,
+
+    /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
+    Secondary,
+}
+
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
-    const STOPS_CONST_CHECKING: bool = false;
-
     /// Returns an enum indicating whether this operation is allowed within the given item.
     fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
         Status::Forbidden
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        let mut err = struct_span_err!(
-            ccx.tcx.sess,
-            span,
-            E0019,
-            "{} contains unimplemented expression type",
-            ccx.const_kind()
-        );
-
-        if let Status::Unstable(gate) = self.status_in_item(ccx) {
-            if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() {
-                err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate));
-            }
-        }
-
-        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
-            err.note(
-                "A function call isn't allowed in the const's initialization expression \
-                      because the expression's value must be known at compile-time.",
-            );
-            err.note(
-                "Remember: you can't use a function call inside a const's initialization \
-                      expression! However, you can use it anywhere else.",
-            );
-        }
-        err.emit();
-    }
-}
-
-#[derive(Debug)]
-pub struct Abort;
-impl NonConstOp for Abort {
-    const STOPS_CONST_CHECKING: bool = true;
-
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        mcf_status_in_item(ccx)
+    fn importance(&self) -> DiagnosticImportance {
+        DiagnosticImportance::Primary
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        mcf_emit_error(ccx, span, "abort is not stable in const fn")
-    }
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
 }
 
 #[derive(Debug)]
 pub struct FloatingPointOp;
 impl NonConstOp for FloatingPointOp {
-    const STOPS_CONST_CHECKING: bool = true;
-
     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
         if ccx.const_kind() == hir::ConstContext::ConstFn {
             Status::Unstable(sym::const_fn_floating_point_arithmetic)
@@ -125,28 +52,13 @@
         }
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_fn_floating_point_arithmetic,
             span,
             &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
         )
-        .emit();
-    }
-}
-
-#[derive(Debug)]
-pub struct NonPrimitiveOp;
-impl NonConstOp for NonPrimitiveOp {
-    const STOPS_CONST_CHECKING: bool = true;
-
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        mcf_status_in_item(ccx)
-    }
-
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        mcf_emit_error(ccx, span, "only int, `bool` and `char` operations are stable in const fn")
     }
 }
 
@@ -154,10 +66,8 @@
 #[derive(Debug)]
 pub struct FnCallIndirect;
 impl NonConstOp for FnCallIndirect {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        let mut err =
-            ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn");
-        err.emit();
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
     }
 }
 
@@ -165,16 +75,15 @@
 #[derive(Debug)]
 pub struct FnCallNonConst(pub DefId);
 impl NonConstOp for FnCallNonConst {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        let mut err = struct_span_err!(
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        struct_span_err!(
             ccx.tcx.sess,
             span,
             E0015,
             "calls in {}s are limited to constant functions, \
              tuple structs and tuple variants",
             ccx.const_kind(),
-        );
-        err.emit();
+        )
     }
 }
 
@@ -185,7 +94,7 @@
 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
 
 impl NonConstOp for FnCallUnstable {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let FnCallUnstable(def_id, feature) = *self;
 
         let mut err = ccx.tcx.sess.struct_span_err(
@@ -203,44 +112,49 @@
                 ));
             }
         }
-        err.emit();
+
+        err
     }
 }
 
 #[derive(Debug)]
 pub struct FnPtrCast;
 impl NonConstOp for FnPtrCast {
-    const STOPS_CONST_CHECKING: bool = true;
-
     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        mcf_status_in_item(ccx)
+        if ccx.const_kind() != hir::ConstContext::ConstFn {
+            Status::Allowed
+        } else {
+            Status::Unstable(sym::const_fn_fn_ptr_basics)
+        }
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        mcf_emit_error(ccx, span, "function pointer casts are not allowed in const fn");
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        feature_err(
+            &ccx.tcx.sess.parse_sess,
+            sym::const_fn_fn_ptr_basics,
+            span,
+            &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
+        )
     }
 }
 
 #[derive(Debug)]
-pub struct Generator;
+pub struct Generator(pub hir::GeneratorKind);
 impl NonConstOp for Generator {
-    const STOPS_CONST_CHECKING: bool = true;
-
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        // FIXME: This means generator-only MIR is only forbidden in const fn. This is for
-        // compatibility with the old code. Such MIR should be forbidden everywhere.
-        mcf_status_in_item(ccx)
+    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+        Status::Forbidden
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        mcf_emit_error(ccx, span, "const fn generators are unstable");
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
+        ccx.tcx.sess.struct_span_err(span, &msg)
     }
 }
 
 #[derive(Debug)]
 pub struct HeapAllocation;
 impl NonConstOp for HeapAllocation {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -257,38 +171,48 @@
                  be done at compile time.",
             );
         }
-        err.emit();
+        err
     }
 }
 
 #[derive(Debug)]
 pub struct InlineAsm;
-impl NonConstOp for InlineAsm {}
+impl NonConstOp for InlineAsm {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        struct_span_err!(
+            ccx.tcx.sess,
+            span,
+            E0015,
+            "inline assembly is not allowed in {}s",
+            ccx.const_kind()
+        )
+    }
+}
 
 #[derive(Debug)]
 pub struct LiveDrop {
     pub dropped_at: Option<Span>,
 }
 impl NonConstOp for LiveDrop {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        let mut diagnostic = struct_span_err!(
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
             E0493,
             "destructors cannot be evaluated at compile-time"
         );
-        diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
+        err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
         if let Some(span) = self.dropped_at {
-            diagnostic.span_label(span, "value is dropped here");
+            err.span_label(span, "value is dropped here");
         }
-        diagnostic.emit();
+        err
     }
 }
 
 #[derive(Debug)]
 pub struct CellBorrow;
 impl NonConstOp for CellBorrow {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -296,12 +220,12 @@
             "cannot borrow a constant which may contain \
             interior mutability, create a static instead"
         )
-        .emit();
     }
 }
 
 #[derive(Debug)]
-pub struct MutBorrow;
+pub struct MutBorrow(pub hir::BorrowKind);
+
 impl NonConstOp for MutBorrow {
     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
         // Forbid everywhere except in const fn with a feature gate
@@ -312,23 +236,29 @@
         }
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        let raw = match self.0 {
+            hir::BorrowKind::Raw => "raw ",
+            hir::BorrowKind::Ref => "",
+        };
+
         let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_mut_refs,
                 span,
-                &format!("mutable references are not allowed in {}s", ccx.const_kind()),
+                &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
             )
         } else {
             let mut err = struct_span_err!(
                 ccx.tcx.sess,
                 span,
                 E0764,
-                "mutable references are not allowed in {}s",
+                "{}mutable references are not allowed in {}s",
+                raw,
                 ccx.const_kind(),
             );
-            err.span_label(span, format!("`&mut` is only allowed in `const fn`"));
+            err.span_label(span, format!("`&{}mut` is only allowed in `const fn`", raw));
             err
         };
         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
@@ -343,31 +273,7 @@
                       static mut or a global UnsafeCell.",
             );
         }
-        err.emit();
-    }
-}
-
-// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
-#[derive(Debug)]
-pub struct MutAddressOf;
-impl NonConstOp for MutAddressOf {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        // Forbid everywhere except in const fn with a feature gate
-        if ccx.const_kind() == hir::ConstContext::ConstFn {
-            Status::Unstable(sym::const_mut_refs)
-        } else {
-            Status::Forbidden
-        }
-    }
-
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_mut_refs,
-            span,
-            &format!("`&raw mut` is not allowed in {}s", ccx.const_kind()),
-        )
-        .emit();
+        err
     }
 }
 
@@ -377,6 +283,20 @@
     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
+
+    fn importance(&self) -> DiagnosticImportance {
+        // Usually a side-effect of a `MutBorrow` somewhere.
+        DiagnosticImportance::Secondary
+    }
+
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        feature_err(
+            &ccx.tcx.sess.parse_sess,
+            sym::const_mut_refs,
+            span,
+            &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()),
+        )
+    }
 }
 
 #[derive(Debug)]
@@ -386,21 +306,20 @@
         Status::Unstable(sym::const_panic)
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_panic,
             span,
             &format!("panicking in {}s is unstable", ccx.const_kind()),
         )
-        .emit();
     }
 }
 
 #[derive(Debug)]
 pub struct RawPtrComparison;
 impl NonConstOp for RawPtrComparison {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = ccx
             .tcx
             .sess
@@ -409,7 +328,7 @@
             "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
             for more information",
         );
-        err.emit();
+        err
     }
 }
 
@@ -420,14 +339,13 @@
         Status::Unstable(sym::const_raw_ptr_deref)
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_raw_ptr_deref,
             span,
             &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),),
         )
-        .emit();
     }
 }
 
@@ -438,14 +356,13 @@
         Status::Unstable(sym::const_raw_ptr_to_usize_cast)
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_raw_ptr_to_usize_cast,
             span,
             &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),),
         )
-        .emit();
     }
 }
 
@@ -461,7 +378,7 @@
         }
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -479,7 +396,7 @@
             );
             err.help("To fix this, the value can be extracted to a `const` and then used.");
         }
-        err.emit();
+        err
     }
 }
 
@@ -487,7 +404,7 @@
 #[derive(Debug)]
 pub struct ThreadLocalAccess;
 impl NonConstOp for ThreadLocalAccess {
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -495,15 +412,12 @@
             "thread-local statics cannot be \
             accessed at compile-time"
         )
-        .emit();
     }
 }
 
 #[derive(Debug)]
 pub struct Transmute;
 impl NonConstOp for Transmute {
-    const STOPS_CONST_CHECKING: bool = true;
-
     fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
         if ccx.const_kind() != hir::ConstContext::ConstFn {
             Status::Allowed
@@ -512,15 +426,15 @@
         }
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        feature_err(
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        let mut err = feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_fn_transmute,
             span,
             &format!("`transmute` is not allowed in {}s", ccx.const_kind()),
-        )
-        .note("`transmute` is only allowed in constants and statics for now")
-        .emit();
+        );
+        err.note("`transmute` is only allowed in constants and statics for now");
+        err
     }
 }
 
@@ -536,14 +450,13 @@
         }
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_fn_union,
             span,
             "unions in const fn are unstable",
         )
-        .emit();
     }
 }
 
@@ -557,12 +470,12 @@
         mcf_status_in_item(ccx)
     }
 
-    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-        mcf_emit_error(
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+        mcf_build_error(
             ccx,
             span,
             "unsizing casts to types besides slices are not allowed in const fn",
-        );
+        )
     }
 }
 
@@ -571,74 +484,100 @@
     use super::*;
 
     #[derive(Debug)]
-    pub struct MutRef;
+    pub struct MutRef(pub mir::LocalKind);
     impl NonConstOp for MutRef {
-        const STOPS_CONST_CHECKING: bool = true;
-
         fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
             Status::Unstable(sym::const_mut_refs)
         }
 
-        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        fn importance(&self) -> DiagnosticImportance {
+            match self.0 {
+                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
+                    DiagnosticImportance::Primary
+                }
+            }
+        }
+
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_mut_refs,
                 span,
                 &format!("mutable references are not allowed in {}s", ccx.const_kind()),
             )
-            .emit()
         }
     }
 
     #[derive(Debug)]
-    pub struct FnPtr;
+    pub struct FnPtr(pub mir::LocalKind);
     impl NonConstOp for FnPtr {
-        const STOPS_CONST_CHECKING: bool = true;
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-            // FIXME: This attribute a hack to allow the specialization of the `futures` API. See
-            // #59739. We should have a proper feature gate for this.
-            if ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_allow_const_fn_ptr) {
-                Status::Allowed
-            } else {
-                mcf_status_in_item(ccx)
+        fn importance(&self) -> DiagnosticImportance {
+            match self.0 {
+                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
+                    DiagnosticImportance::Primary
+                }
             }
         }
 
-        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-            mcf_emit_error(ccx, span, "function pointers in const fn are unstable");
+        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+            if ccx.const_kind() != hir::ConstContext::ConstFn {
+                Status::Allowed
+            } else {
+                Status::Unstable(sym::const_fn_fn_ptr_basics)
+            }
+        }
+
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+            feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_fn_fn_ptr_basics,
+                span,
+                &format!("function pointers cannot appear in {}s", ccx.const_kind()),
+            )
         }
     }
 
     #[derive(Debug)]
     pub struct ImplTrait;
     impl NonConstOp for ImplTrait {
-        const STOPS_CONST_CHECKING: bool = true;
-
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-            mcf_status_in_item(ccx)
+        fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+            Status::Unstable(sym::const_impl_trait)
         }
 
-        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-            mcf_emit_error(ccx, span, "`impl Trait` in const fn is unstable");
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+            feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_impl_trait,
+                span,
+                &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
+            )
         }
     }
 
     #[derive(Debug)]
-    pub struct TraitBound;
+    pub struct TraitBound(pub mir::LocalKind);
     impl NonConstOp for TraitBound {
-        const STOPS_CONST_CHECKING: bool = true;
+        fn importance(&self) -> DiagnosticImportance {
+            match self.0 {
+                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
+                    DiagnosticImportance::Primary
+                }
+            }
+        }
 
         fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
             mcf_status_in_item(ccx)
         }
 
-        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
-            mcf_emit_error(
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+            mcf_build_error(
                 ccx,
                 span,
                 "trait bounds other than `Sized` on const fn parameters are unstable",
-            );
+            )
         }
     }
 
@@ -646,20 +585,17 @@
     #[derive(Debug)]
     pub struct TraitBoundNotConst;
     impl NonConstOp for TraitBoundNotConst {
-        const STOPS_CONST_CHECKING: bool = true;
-
         fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
             Status::Unstable(sym::const_trait_bound_opt_out)
         }
 
-        fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_trait_bound_opt_out,
                 span,
                 "`?const Trait` syntax is unstable",
             )
-            .emit()
         }
     }
 }
@@ -672,12 +608,12 @@
     }
 }
 
-fn mcf_emit_error(ccx: &ConstCx<'_, '_>, span: Span, msg: &str) {
-    struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg)
-        .note(
-            "see issue #57563 <https://github.com/rust-lang/rust/issues/57563> \
+fn mcf_build_error(ccx: &ConstCx<'_, 'tcx>, span: Span, msg: &str) -> DiagnosticBuilder<'tcx> {
+    let mut err = struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg);
+    err.note(
+        "see issue #57563 <https://github.com/rust-lang/rust/issues/57563> \
              for more information",
-        )
-        .help("add `#![feature(const_fn)]` to the crate attributes to enable")
-        .emit();
+    );
+    err.help("add `#![feature(const_fn)]` to the crate attributes to enable");
+    err
 }
diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
index 0c171bb..1a2d932 100644
--- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
@@ -1,10 +1,9 @@
-use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{self, BasicBlock, Location};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 
-use super::ops;
+use super::ops::{self, NonConstOp};
 use super::qualifs::{NeedsDrop, Qualif};
 use super::validation::Qualifs;
 use super::ConstCx;
@@ -24,13 +23,14 @@
 ///
 /// This is separate from the rest of the const checking logic because it must run after drop
 /// elaboration.
-pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<'tcx>) {
+pub fn check_live_drops(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
+    let def_id = body.source.def_id().expect_local();
     let const_kind = tcx.hir().body_const_context(def_id);
     if const_kind.is_none() {
         return;
     }
 
-    let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
+    let ccx = ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def_id) };
     if !checking_enabled(&ccx) {
         return;
     }
@@ -56,7 +56,7 @@
 
 impl CheckLiveDrops<'mir, 'tcx> {
     fn check_live_drop(&self, span: Span) {
-        ops::non_const(self.ccx, ops::LiveDrop { dropped_at: None }, span);
+        ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit();
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
index 3f4b3ca..b3d9beb 100644
--- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
@@ -126,7 +126,7 @@
         // because that component may be part of an enum variant (e.g.,
         // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
         // structural-match (`Option::None`).
-        let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id);
+        let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id());
         traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
     }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index ee6adbc..c991eb4 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -1,8 +1,8 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
-use rustc_errors::struct_span_err;
-use rustc_hir::{self as hir, LangItem};
-use rustc_hir::{def_id::DefId, HirId};
+use rustc_errors::{struct_span_err, Applicability, Diagnostic};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, HirId, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -11,13 +11,14 @@
 use rustc_middle::ty::{
     self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut,
 };
-use rustc_span::{sym, Span};
+use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, TraitEngine};
 
+use std::mem;
 use std::ops::Deref;
 
-use super::ops::{self, NonConstOp};
+use super::ops::{self, NonConstOp, Status};
 use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{is_lang_panic_fn, ConstCx, Qualif};
@@ -49,7 +50,7 @@
         location: Location,
     ) -> bool {
         let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
-            let ConstCx { tcx, body, def_id, param_env, .. } = *ccx;
+            let ConstCx { tcx, body, param_env, .. } = *ccx;
 
             // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
             // allowed in a const.
@@ -58,7 +59,7 @@
             // without breaking stable code?
             MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
                 .unsound_ignore_borrow_on_drop()
-                .into_engine(tcx, &body, def_id.to_def_id())
+                .into_engine(tcx, &body)
                 .pass_name("const_qualification")
                 .iterate_to_fixpoint()
                 .into_results_cursor(&body)
@@ -83,10 +84,10 @@
         }
 
         let needs_drop = self.needs_drop.get_or_insert_with(|| {
-            let ConstCx { tcx, body, def_id, .. } = *ccx;
+            let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(NeedsDrop, ccx)
-                .into_engine(tcx, &body, def_id.to_def_id())
+                .into_engine(tcx, &body)
                 .iterate_to_fixpoint()
                 .into_results_cursor(&body)
         });
@@ -110,10 +111,10 @@
         }
 
         let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| {
-            let ConstCx { tcx, body, def_id, .. } = *ccx;
+            let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(HasMutInterior, ccx)
-                .into_engine(tcx, &body, def_id.to_def_id())
+                .into_engine(tcx, &body)
                 .iterate_to_fixpoint()
                 .into_results_cursor(&body)
         });
@@ -156,7 +157,7 @@
 
             hir::ConstContext::Const | hir::ConstContext::Static(_) => {
                 let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
-                    .into_engine(ccx.tcx, &ccx.body, ccx.def_id.to_def_id())
+                    .into_engine(ccx.tcx, &ccx.body)
                     .iterate_to_fixpoint()
                     .into_results_cursor(&ccx.body);
 
@@ -180,7 +181,8 @@
     /// The span of the current statement.
     span: Span,
 
-    const_checking_stopped: bool,
+    error_emitted: bool,
+    secondary_errors: Vec<Diagnostic>,
 }
 
 impl Deref for Validator<'mir, 'tcx> {
@@ -197,19 +199,28 @@
             span: ccx.body.span,
             ccx,
             qualifs: Default::default(),
-            const_checking_stopped: false,
+            error_emitted: false,
+            secondary_errors: Vec::new(),
         }
     }
 
     pub fn check_body(&mut self) {
-        let ConstCx { tcx, body, def_id, .. } = *self.ccx;
+        let ConstCx { tcx, body, .. } = *self.ccx;
+        let def_id = self.ccx.def_id();
+
+        // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's
+        // no need to emit duplicate errors here.
+        if is_async_fn(self.ccx) || body.generator_kind.is_some() {
+            tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`");
+            return;
+        }
 
         // The local type and predicate checks are not free and only relevant for `const fn`s.
         if self.const_kind() == hir::ConstContext::ConstFn {
             // Prevent const trait methods from being annotated as `stable`.
             // FIXME: Do this as part of stability checking.
             if self.is_const_stable_const_fn() {
-                let hir_id = tcx.hir().local_def_id_to_hir_id(self.def_id);
+                let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
                 if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
                     struct_span_err!(
                         self.ccx.tcx.sess,
@@ -223,20 +234,21 @@
 
             self.check_item_predicates();
 
-            for local in &body.local_decls {
-                if local.internal {
+            for (idx, local) in body.local_decls.iter_enumerated() {
+                // Handle the return place below.
+                if idx == RETURN_PLACE || local.internal {
                     continue;
                 }
 
                 self.span = local.source_info.span;
-                self.check_local_or_return_ty(local.ty);
+                self.check_local_or_return_ty(local.ty, idx);
             }
 
             // impl trait is gone in MIR, so check the return type of a const fn by its signature
             // instead of the type of the return place.
             self.span = body.local_decls[RETURN_PLACE].source_info.span;
             let return_ty = tcx.fn_sig(def_id).output();
-            self.check_local_or_return_ty(return_ty.skip_binder());
+            self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
         }
 
         self.visit_body(&body);
@@ -250,6 +262,17 @@
             let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
             check_return_ty_is_sync(tcx, &body, hir_id);
         }
+
+        // If we got through const-checking without emitting any "primary" errors, emit any
+        // "secondary" errors if they occurred.
+        let secondary_errors = mem::take(&mut self.secondary_errors);
+        if !self.error_emitted {
+            for error in secondary_errors {
+                self.tcx.sess.diagnostic().emit_diagnostic(&error);
+            }
+        } else {
+            assert!(self.tcx.sess.has_errors());
+        }
     }
 
     pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
@@ -264,15 +287,38 @@
     /// Emits an error at the given `span` if an expression cannot be evaluated in the current
     /// context.
     pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
-        // HACK: This is for strict equivalence with the old `qualify_min_const_fn` pass, which
-        // only emitted one error per function. It should be removed and the test output updated.
-        if self.const_checking_stopped {
+        let gate = match op.status_in_item(self.ccx) {
+            Status::Allowed => return,
+
+            Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
+                let unstable_in_stable = self.ccx.is_const_stable_const_fn()
+                    && !super::allow_internal_unstable(self.tcx, self.def_id().to_def_id(), gate);
+                if unstable_in_stable {
+                    emit_unstable_in_stable_error(self.ccx, span, gate);
+                }
+
+                return;
+            }
+
+            Status::Unstable(gate) => Some(gate),
+            Status::Forbidden => None,
+        };
+
+        if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
+            self.tcx.sess.miri_unleashed_feature(span, gate);
             return;
         }
 
-        let err_emitted = ops::non_const(self.ccx, op, span);
-        if err_emitted && O::STOPS_CONST_CHECKING {
-            self.const_checking_stopped = true;
+        let mut err = op.build_error(self.ccx, span);
+        assert!(err.is_error());
+
+        match op.importance() {
+            ops::DiagnosticImportance::Primary => {
+                self.error_emitted = true;
+                err.emit();
+            }
+
+            ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors),
         }
     }
 
@@ -284,7 +330,9 @@
         self.check_op_spanned(ops::StaticAccess, span)
     }
 
-    fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) {
+    fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
+        let kind = self.body.local_kind(local);
+
         for ty in ty.walk() {
             let ty = match ty.unpack() {
                 GenericArgKind::Type(ty) => ty,
@@ -295,20 +343,20 @@
             };
 
             match *ty.kind() {
-                ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef),
+                ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
                 ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
-                ty::FnPtr(..) => self.check_op(ops::ty::FnPtr),
+                ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
 
                 ty::Dynamic(preds, _) => {
                     for pred in preds.iter() {
                         match pred.skip_binder() {
                             ty::ExistentialPredicate::AutoTrait(_)
                             | ty::ExistentialPredicate::Projection(_) => {
-                                self.check_op(ops::ty::TraitBound)
+                                self.check_op(ops::ty::TraitBound(kind))
                             }
                             ty::ExistentialPredicate::Trait(trait_ref) => {
                                 if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
-                                    self.check_op(ops::ty::TraitBound)
+                                    self.check_op(ops::ty::TraitBound(kind))
                                 }
                             }
                         }
@@ -320,9 +368,9 @@
     }
 
     fn check_item_predicates(&mut self) {
-        let ConstCx { tcx, def_id, .. } = *self.ccx;
+        let ConstCx { tcx, .. } = *self.ccx;
 
-        let mut current = def_id.to_def_id();
+        let mut current = self.def_id().to_def_id();
         loop {
             let predicates = tcx.predicates_of(current);
             for (predicate, _) in predicates.predicates {
@@ -353,15 +401,19 @@
                                 let def = generics.type_param(p, tcx);
                                 let span = tcx.def_span(def.def_id);
 
+                                // These are part of the function signature, so treat them like
+                                // arguments when determining importance.
+                                let kind = LocalKind::Arg;
+
                                 if constness == hir::Constness::Const {
-                                    self.check_op_spanned(ops::ty::TraitBound, span);
+                                    self.check_op_spanned(ops::ty::TraitBound(kind), span);
                                 } else if !tcx.features().const_fn
                                     || self.ccx.is_const_stable_const_fn()
                                 {
                                     // HACK: We shouldn't need the conditional above, but trait
                                     // bounds on containing impl blocks are wrongly being marked as
                                     // "not-const".
-                                    self.check_op_spanned(ops::ty::TraitBound, span);
+                                    self.check_op_spanned(ops::ty::TraitBound(kind), span);
                                 }
                             }
                             // other kinds of bounds are either tautologies
@@ -383,11 +435,13 @@
     fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
         trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
 
-        // Just as the old checker did, we skip const-checking basic blocks on the unwind path.
-        // These blocks often drop locals that would otherwise be returned from the function.
+        // We don't const-check basic blocks on the cleanup path since we never unwind during
+        // const-eval: a panic causes an immediate compile error. In other words, cleanup blocks
+        // are unreachable during const-eval.
         //
-        // FIXME: This shouldn't be unsound since a panic at compile time will cause a compiler
-        // error anyway, but maybe we should do more here?
+        // We can't be more conservative (e.g., by const-checking cleanup blocks anyways) because
+        // locals that would never be dropped during normal execution are sometimes dropped during
+        // unwinding, which means backwards-incompatible live-drop errors.
         if block.is_cleanup {
             return;
         }
@@ -471,14 +525,16 @@
 
                 if !is_allowed {
                     if let BorrowKind::Mut { .. } = kind {
-                        self.check_op(ops::MutBorrow);
+                        self.check_op(ops::MutBorrow(hir::BorrowKind::Ref));
                     } else {
                         self.check_op(ops::CellBorrow);
                     }
                 }
             }
 
-            Rvalue::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf),
+            Rvalue::AddressOf(Mutability::Mut, _) => {
+                self.check_op(ops::MutBorrow(hir::BorrowKind::Raw))
+            }
 
             Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place)
             | Rvalue::AddressOf(Mutability::Not, ref place) => {
@@ -683,8 +739,8 @@
 
         match &terminator.kind {
             TerminatorKind::Call { func, .. } => {
-                let ConstCx { tcx, body, def_id: caller, param_env, .. } = *self.ccx;
-                let caller = caller.to_def_id();
+                let ConstCx { tcx, body, param_env, .. } = *self.ccx;
+                let caller = self.def_id().to_def_id();
 
                 let fn_ty = func.ty(body, tcx);
 
@@ -719,6 +775,14 @@
                     return;
                 }
 
+                // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`.
+                let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn();
+                if is_async_block {
+                    let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block);
+                    self.check_op(ops::Generator(kind));
+                    return;
+                }
+
                 // HACK: This is to "unstabilize" the `transmute` intrinsic
                 // within const fns. `transmute` is allowed in all other const contexts.
                 // This won't really scale to more intrinsics or functions. Let's allow const
@@ -815,10 +879,14 @@
             }
 
             TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
-            TerminatorKind::Abort => self.check_op(ops::Abort),
 
             TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
-                self.check_op(ops::Generator)
+                self.check_op(ops::Generator(hir::GeneratorKind::Gen))
+            }
+
+            TerminatorKind::Abort => {
+                // Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
+                span_bug!(self.span, "`Abort` terminator outside of cleanup block")
             }
 
             TerminatorKind::Assert { .. }
@@ -877,3 +945,31 @@
 fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
     ty.is_bool() || ty.is_integral() || ty.is_char()
 }
+
+fn is_async_fn(ccx: &ConstCx<'_, '_>) -> bool {
+    ccx.fn_sig().map_or(false, |sig| sig.header.asyncness == hir::IsAsync::Async)
+}
+
+fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
+    let attr_span = ccx.fn_sig().map_or(ccx.body.span, |sig| sig.span.shrink_to_lo());
+
+    ccx.tcx
+        .sess
+        .struct_span_err(
+            span,
+            &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
+        )
+        .span_suggestion(
+            attr_span,
+            "if it is not part of the public API, make this function unstably const",
+            concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
+            Applicability::HasPlaceholders,
+        )
+        .span_suggestion(
+            attr_span,
+            "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks",
+            format!("#[allow_internal_unstable({})]\n", gate),
+            Applicability::MaybeIncorrect,
+        )
+        .emit();
+}
diff --git a/compiler/rustc_mir/src/transform/check_packed_ref.rs b/compiler/rustc_mir/src/transform/check_packed_ref.rs
index 043b2d0..ee88daa 100644
--- a/compiler/rustc_mir/src/transform/check_packed_ref.rs
+++ b/compiler/rustc_mir/src/transform/check_packed_ref.rs
@@ -3,14 +3,14 @@
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util;
 
 pub struct CheckPackedRef;
 
 impl<'tcx> MirPass<'tcx> for CheckPackedRef {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(src.instance.def_id());
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let param_env = tcx.param_env(body.source.def_id());
         let source_info = SourceInfo::outermost(body.span);
         let mut checker = PackedRefChecker { body, tcx, param_env, source_info };
         checker.visit_body(&body);
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index 7309a41..3d68b86 100644
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ b/compiler/rustc_mir/src/transform/check_unsafety.rs
@@ -204,6 +204,9 @@
             if let [] = proj_base {
                 let decl = &self.body.local_decls[place.local];
                 if decl.internal {
+                    // If the projection root is an artifical local that we introduced when
+                    // desugaring `static`, give a more specific error message
+                    // (avoid the general "raw pointer" clause below, that would only be confusing).
                     if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
                         if self.tcx.is_mutable_static(def_id) {
                             self.require_unsafe(
diff --git a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs b/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
index 3f3d247..8ff0fae 100644
--- a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
@@ -18,7 +18,7 @@
 //! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard
 //! [`Nop`]: rustc_middle::mir::StatementKind::Nop
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue};
 use rustc_middle::mir::{Statement, StatementKind};
@@ -31,7 +31,7 @@
 }
 
 impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut delete = DeleteNonCodegenStatements { tcx };
         delete.visit_body(body);
         body.user_type_annotations.raw.clear();
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index 0f04ead..14b310c 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -32,7 +32,7 @@
     InterpCx, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand,
     PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup,
 };
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
 /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
@@ -60,30 +60,31 @@
 pub struct ConstProp;
 
 impl<'tcx> MirPass<'tcx> for ConstProp {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // will be evaluated by miri and produce its errors there
-        if source.promoted.is_some() {
+        if body.source.promoted.is_some() {
             return;
         }
 
         use rustc_middle::hir::map::blocks::FnLikeNode;
-        let hir_id = tcx.hir().local_def_id_to_hir_id(source.def_id().expect_local());
+        let def_id = body.source.def_id().expect_local();
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
         let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
-        let is_assoc_const = tcx.def_kind(source.def_id()) == DefKind::AssocConst;
+        let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst;
 
         // Only run const prop on functions, methods, closures and associated constants
         if !is_fn_like && !is_assoc_const {
             // skip anon_const/statics/consts because they'll be evaluated by miri anyway
-            trace!("ConstProp skipped for {:?}", source.def_id());
+            trace!("ConstProp skipped for {:?}", def_id);
             return;
         }
 
-        let is_generator = tcx.type_of(source.def_id()).is_generator();
+        let is_generator = tcx.type_of(def_id.to_def_id()).is_generator();
         // FIXME(welseywiser) const prop doesn't work on generators because of query cycles
         // computing their layout.
         if is_generator {
-            trace!("ConstProp skipped for generator {:?}", source.def_id());
+            trace!("ConstProp skipped for generator {:?}", def_id);
             return;
         }
 
@@ -114,7 +115,7 @@
         // the normalization code (leading to cycle errors), since
         // it's usually never invoked in this way.
         let predicates = tcx
-            .predicates_of(source.def_id())
+            .predicates_of(def_id.to_def_id())
             .predicates
             .iter()
             .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
@@ -122,20 +123,21 @@
             tcx,
             traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
         ) {
-            trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", source.def_id());
+            trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
             return;
         }
 
-        trace!("ConstProp starting for {:?}", source.def_id());
+        trace!("ConstProp starting for {:?}", def_id);
 
         let dummy_body = &Body::new(
+            body.source,
             body.basic_blocks().clone(),
             body.source_scopes.clone(),
             body.local_decls.clone(),
             Default::default(),
             body.arg_count,
             Default::default(),
-            tcx.def_span(source.def_id()),
+            tcx.def_span(def_id),
             body.generator_kind,
         );
 
@@ -143,10 +145,10 @@
         // constants, instead of just checking for const-folding succeeding.
         // That would require an uniform one-def no-mutation analysis
         // and RPO (or recursing when needing the value of a local).
-        let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx, source);
+        let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
         optimization_finder.visit_body(body);
 
-        trace!("ConstProp done for {:?}", source.def_id());
+        trace!("ConstProp done for {:?}", def_id);
     }
 }
 
@@ -346,9 +348,8 @@
         body: &Body<'tcx>,
         dummy_body: &'mir Body<'tcx>,
         tcx: TyCtxt<'tcx>,
-        source: MirSource<'tcx>,
     ) -> ConstPropagator<'mir, 'tcx> {
-        let def_id = source.def_id();
+        let def_id = body.source.def_id();
         let substs = &InternalSubsts::identity_for_item(tcx, def_id);
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
diff --git a/compiler/rustc_mir/src/transform/copy_prop.rs b/compiler/rustc_mir/src/transform/copy_prop.rs
deleted file mode 100644
index ba406c7..0000000
--- a/compiler/rustc_mir/src/transform/copy_prop.rs
+++ /dev/null
@@ -1,382 +0,0 @@
-//! Trivial copy propagation pass.
-//!
-//! This uses def-use analysis to remove values that have exactly one def and one use, which must
-//! be an assignment.
-//!
-//! To give an example, we look for patterns that look like:
-//!
-//!     DEST = SRC
-//!     ...
-//!     USE(DEST)
-//!
-//! where `DEST` and `SRC` are both locals of some form. We replace that with:
-//!
-//!     NOP
-//!     ...
-//!     USE(SRC)
-//!
-//! The assignment `DEST = SRC` must be (a) the only mutation of `DEST` and (b) the only
-//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
-//! future.
-
-use crate::transform::{MirPass, MirSource};
-use crate::util::def_use::DefUseAnalysis;
-use rustc_middle::mir::visit::MutVisitor;
-use rustc_middle::mir::{
-    Body, Constant, Local, LocalKind, Location, Operand, Place, Rvalue, StatementKind,
-};
-use rustc_middle::ty::TyCtxt;
-
-pub struct CopyPropagation;
-
-impl<'tcx> MirPass<'tcx> for CopyPropagation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        // We only run when the MIR optimization level is > 1.
-        // This avoids a slow pass, and messing up debug info.
-        if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
-            return;
-        }
-
-        let mut def_use_analysis = DefUseAnalysis::new(body);
-        loop {
-            def_use_analysis.analyze(body);
-
-            if eliminate_self_assignments(body, &def_use_analysis) {
-                def_use_analysis.analyze(body);
-            }
-
-            let mut changed = false;
-            for dest_local in body.local_decls.indices() {
-                debug!("considering destination local: {:?}", dest_local);
-
-                let action;
-                let location;
-                {
-                    // The destination must have exactly one def.
-                    let dest_use_info = def_use_analysis.local_info(dest_local);
-                    let dest_def_count = dest_use_info.def_count_not_including_drop();
-                    if dest_def_count == 0 {
-                        debug!("  Can't copy-propagate local: dest {:?} undefined", dest_local);
-                        continue;
-                    }
-                    if dest_def_count > 1 {
-                        debug!(
-                            "  Can't copy-propagate local: dest {:?} defined {} times",
-                            dest_local,
-                            dest_use_info.def_count()
-                        );
-                        continue;
-                    }
-                    if dest_use_info.use_count() == 0 {
-                        debug!("  Can't copy-propagate local: dest {:?} unused", dest_local);
-                        continue;
-                    }
-                    // Conservatively gives up if the dest is an argument,
-                    // because there may be uses of the original argument value.
-                    // Also gives up on the return place, as we cannot propagate into its implicit
-                    // use by `return`.
-                    if matches!(
-                        body.local_kind(dest_local),
-                        LocalKind::Arg | LocalKind::ReturnPointer
-                    ) {
-                        debug!("  Can't copy-propagate local: dest {:?} (argument)", dest_local);
-                        continue;
-                    }
-                    let dest_place_def = dest_use_info.defs_not_including_drop().next().unwrap();
-                    location = dest_place_def.location;
-
-                    let basic_block = &body[location.block];
-                    let statement_index = location.statement_index;
-                    let statement = match basic_block.statements.get(statement_index) {
-                        Some(statement) => statement,
-                        None => {
-                            debug!("  Can't copy-propagate local: used in terminator");
-                            continue;
-                        }
-                    };
-
-                    // That use of the source must be an assignment.
-                    match &statement.kind {
-                        StatementKind::Assign(box (place, Rvalue::Use(operand))) => {
-                            if let Some(local) = place.as_local() {
-                                if local == dest_local {
-                                    let maybe_action = match operand {
-                                        Operand::Copy(src_place) | Operand::Move(src_place) => {
-                                            Action::local_copy(&body, &def_use_analysis, *src_place)
-                                        }
-                                        Operand::Constant(ref src_constant) => {
-                                            Action::constant(src_constant)
-                                        }
-                                    };
-                                    match maybe_action {
-                                        Some(this_action) => action = this_action,
-                                        None => continue,
-                                    }
-                                } else {
-                                    debug!(
-                                        "  Can't copy-propagate local: source use is not an \
-                                    assignment"
-                                    );
-                                    continue;
-                                }
-                            } else {
-                                debug!(
-                                    "  Can't copy-propagate local: source use is not an \
-                                    assignment"
-                                );
-                                continue;
-                            }
-                        }
-                        _ => {
-                            debug!(
-                                "  Can't copy-propagate local: source use is not an \
-                                    assignment"
-                            );
-                            continue;
-                        }
-                    }
-                }
-
-                changed =
-                    action.perform(body, &def_use_analysis, dest_local, location, tcx) || changed;
-                // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of
-                // regenerating the chains.
-                break;
-            }
-            if !changed {
-                break;
-            }
-        }
-    }
-}
-
-fn eliminate_self_assignments(body: &mut Body<'_>, def_use_analysis: &DefUseAnalysis) -> bool {
-    let mut changed = false;
-
-    for dest_local in body.local_decls.indices() {
-        let dest_use_info = def_use_analysis.local_info(dest_local);
-
-        for def in dest_use_info.defs_not_including_drop() {
-            let location = def.location;
-            if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
-                match &stmt.kind {
-                    StatementKind::Assign(box (
-                        place,
-                        Rvalue::Use(Operand::Copy(src_place) | Operand::Move(src_place)),
-                    )) => {
-                        if let (Some(local), Some(src_local)) =
-                            (place.as_local(), src_place.as_local())
-                        {
-                            if local == dest_local && dest_local == src_local {
-                            } else {
-                                continue;
-                            }
-                        } else {
-                            continue;
-                        }
-                    }
-                    _ => {
-                        continue;
-                    }
-                }
-            } else {
-                continue;
-            }
-            debug!("deleting a self-assignment for {:?}", dest_local);
-            body.make_statement_nop(location);
-            changed = true;
-        }
-    }
-
-    changed
-}
-
-enum Action<'tcx> {
-    PropagateLocalCopy(Local),
-    PropagateConstant(Constant<'tcx>),
-}
-
-impl<'tcx> Action<'tcx> {
-    fn local_copy(
-        body: &Body<'tcx>,
-        def_use_analysis: &DefUseAnalysis,
-        src_place: Place<'tcx>,
-    ) -> Option<Action<'tcx>> {
-        // The source must be a local.
-        let src_local = if let Some(local) = src_place.as_local() {
-            local
-        } else {
-            debug!("  Can't copy-propagate local: source is not a local");
-            return None;
-        };
-
-        // We're trying to copy propagate a local.
-        // There must be exactly one use of the source used in a statement (not in a terminator).
-        let src_use_info = def_use_analysis.local_info(src_local);
-        let src_use_count = src_use_info.use_count();
-        if src_use_count == 0 {
-            debug!("  Can't copy-propagate local: no uses");
-            return None;
-        }
-        if src_use_count != 1 {
-            debug!("  Can't copy-propagate local: {} uses", src_use_info.use_count());
-            return None;
-        }
-
-        // Verify that the source doesn't change in between. This is done conservatively for now,
-        // by ensuring that the source has exactly one mutation. The goal is to prevent things
-        // like:
-        //
-        //     DEST = SRC;
-        //     SRC = X;
-        //     USE(DEST);
-        //
-        // From being misoptimized into:
-        //
-        //     SRC = X;
-        //     USE(SRC);
-        let src_def_count = src_use_info.def_count_not_including_drop();
-        // allow function arguments to be propagated
-        let is_arg = body.local_kind(src_local) == LocalKind::Arg;
-        if (is_arg && src_def_count != 0) || (!is_arg && src_def_count != 1) {
-            debug!(
-                "  Can't copy-propagate local: {} defs of src{}",
-                src_def_count,
-                if is_arg { " (argument)" } else { "" },
-            );
-            return None;
-        }
-
-        Some(Action::PropagateLocalCopy(src_local))
-    }
-
-    fn constant(src_constant: &Constant<'tcx>) -> Option<Action<'tcx>> {
-        Some(Action::PropagateConstant(*src_constant))
-    }
-
-    fn perform(
-        self,
-        body: &mut Body<'tcx>,
-        def_use_analysis: &DefUseAnalysis,
-        dest_local: Local,
-        location: Location,
-        tcx: TyCtxt<'tcx>,
-    ) -> bool {
-        match self {
-            Action::PropagateLocalCopy(src_local) => {
-                // Eliminate the destination and the assignment.
-                //
-                // First, remove all markers.
-                //
-                // FIXME(pcwalton): Don't do this. Merge live ranges instead.
-                debug!("  Replacing all uses of {:?} with {:?} (local)", dest_local, src_local);
-                for place_use in &def_use_analysis.local_info(dest_local).defs_and_uses {
-                    if place_use.context.is_storage_marker() {
-                        body.make_statement_nop(place_use.location)
-                    }
-                }
-                for place_use in &def_use_analysis.local_info(src_local).defs_and_uses {
-                    if place_use.context.is_storage_marker() {
-                        body.make_statement_nop(place_use.location)
-                    }
-                }
-
-                // Replace all uses of the destination local with the source local.
-                def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local, tcx);
-
-                // Finally, zap the now-useless assignment instruction.
-                debug!("  Deleting assignment");
-                body.make_statement_nop(location);
-
-                true
-            }
-            Action::PropagateConstant(src_constant) => {
-                // First, remove all markers.
-                //
-                // FIXME(pcwalton): Don't do this. Merge live ranges instead.
-                debug!(
-                    "  Replacing all uses of {:?} with {:?} (constant)",
-                    dest_local, src_constant
-                );
-                let dest_local_info = def_use_analysis.local_info(dest_local);
-                for place_use in &dest_local_info.defs_and_uses {
-                    if place_use.context.is_storage_marker() {
-                        body.make_statement_nop(place_use.location)
-                    }
-                }
-
-                // Replace all uses of the destination local with the constant.
-                let mut visitor = ConstantPropagationVisitor::new(dest_local, src_constant, tcx);
-                for dest_place_use in &dest_local_info.defs_and_uses {
-                    visitor.visit_location(body, dest_place_use.location)
-                }
-
-                // Zap the assignment instruction if we eliminated all the uses. We won't have been
-                // able to do that if the destination was used in a projection, because projections
-                // must have places on their LHS.
-                let use_count = dest_local_info.use_count();
-                if visitor.uses_replaced == use_count {
-                    debug!(
-                        "  {} of {} use(s) replaced; deleting assignment",
-                        visitor.uses_replaced, use_count
-                    );
-                    body.make_statement_nop(location);
-                    true
-                } else if visitor.uses_replaced == 0 {
-                    debug!("  No uses replaced; not deleting assignment");
-                    false
-                } else {
-                    debug!(
-                        "  {} of {} use(s) replaced; not deleting assignment",
-                        visitor.uses_replaced, use_count
-                    );
-                    true
-                }
-            }
-        }
-    }
-}
-
-struct ConstantPropagationVisitor<'tcx> {
-    dest_local: Local,
-    constant: Constant<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    uses_replaced: usize,
-}
-
-impl<'tcx> ConstantPropagationVisitor<'tcx> {
-    fn new(
-        dest_local: Local,
-        constant: Constant<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> ConstantPropagationVisitor<'tcx> {
-        ConstantPropagationVisitor { dest_local, constant, tcx, uses_replaced: 0 }
-    }
-}
-
-impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
-        self.super_operand(operand, location);
-
-        match operand {
-            Operand::Copy(place) | Operand::Move(place) => {
-                if let Some(local) = place.as_local() {
-                    if local == self.dest_local {
-                    } else {
-                        return;
-                    }
-                } else {
-                    return;
-                }
-            }
-            _ => return,
-        }
-
-        *operand = Operand::Constant(box self.constant);
-        self.uses_replaced += 1
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/deaggregator.rs b/compiler/rustc_mir/src/transform/deaggregator.rs
index 66989a9..5bd7256 100644
--- a/compiler/rustc_mir/src/transform/deaggregator.rs
+++ b/compiler/rustc_mir/src/transform/deaggregator.rs
@@ -1,4 +1,4 @@
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util::expand_aggregate;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -6,7 +6,7 @@
 pub struct Deaggregator;
 
 impl<'tcx> MirPass<'tcx> for Deaggregator {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         let local_decls = &*local_decls;
         for bb in basic_blocks {
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
index 97d2617..410f462 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir/src/transform/dest_prop.rs
@@ -99,7 +99,7 @@
 use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
 use crate::dataflow::Analysis;
 use crate::{
-    transform::{MirPass, MirSource},
+    transform::MirPass,
     util::{dump_mir, PassWhere},
 };
 use itertools::Itertools;
@@ -126,16 +126,18 @@
 pub struct DestinationPropagation;
 
 impl<'tcx> MirPass<'tcx> for DestinationPropagation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove
         // storage statements at the moment).
         if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
             return;
         }
 
+        let def_id = body.source.def_id();
+
         let candidates = find_candidates(tcx, body);
         if candidates.is_empty() {
-            debug!("{:?}: no dest prop candidates, done", source.def_id());
+            debug!("{:?}: no dest prop candidates, done", def_id);
             return;
         }
 
@@ -152,7 +154,7 @@
         let relevant = relevant_locals.count();
         debug!(
             "{:?}: {} locals ({} relevant), {} blocks",
-            source.def_id(),
+            def_id,
             body.local_decls.len(),
             relevant,
             body.basic_blocks().len()
@@ -160,23 +162,21 @@
         if relevant > MAX_LOCALS {
             warn!(
                 "too many candidate locals in {:?} ({}, max is {}), not optimizing",
-                source.def_id(),
-                relevant,
-                MAX_LOCALS
+                def_id, relevant, MAX_LOCALS
             );
             return;
         }
         if body.basic_blocks().len() > MAX_BLOCKS {
             warn!(
                 "too many blocks in {:?} ({}, max is {}), not optimizing",
-                source.def_id(),
+                def_id,
                 body.basic_blocks().len(),
                 MAX_BLOCKS
             );
             return;
         }
 
-        let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals);
+        let mut conflicts = Conflicts::build(tcx, body, &relevant_locals);
 
         let mut replacements = Replacements::new(body.local_decls.len());
         for candidate @ CandidateAssignment { dest, src, loc } in candidates {
@@ -192,7 +192,7 @@
             }
 
             if !tcx.consider_optimizing(|| {
-                format!("DestinationPropagation {:?} {:?}", source.def_id(), candidate)
+                format!("DestinationPropagation {:?} {:?}", def_id, candidate)
             }) {
                 break;
             }
@@ -398,7 +398,6 @@
     fn build<'tcx>(
         tcx: TyCtxt<'tcx>,
         body: &'_ Body<'tcx>,
-        source: MirSource<'tcx>,
         relevant_locals: &'a BitSet<Local>,
     ) -> Self {
         // We don't have to look out for locals that have their address taken, since
@@ -409,69 +408,57 @@
             body.local_decls.len(),
         );
 
-        let def_id = source.def_id();
         let mut init = MaybeInitializedLocals
-            .into_engine(tcx, body, def_id)
+            .into_engine(tcx, body)
             .iterate_to_fixpoint()
             .into_results_cursor(body);
-        let mut live = MaybeLiveLocals
-            .into_engine(tcx, body, def_id)
-            .iterate_to_fixpoint()
-            .into_results_cursor(body);
+        let mut live =
+            MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint().into_results_cursor(body);
 
         let mut reachable = None;
-        dump_mir(
-            tcx,
-            None,
-            "DestinationPropagation-dataflow",
-            &"",
-            source,
-            body,
-            |pass_where, w| {
-                let reachable =
-                    reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
+        dump_mir(tcx, None, "DestinationPropagation-dataflow", &"", body, |pass_where, w| {
+            let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
 
-                match pass_where {
-                    PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
-                        init.seek_before_primary_effect(loc);
-                        live.seek_after_primary_effect(loc);
+            match pass_where {
+                PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
+                    init.seek_before_primary_effect(loc);
+                    live.seek_after_primary_effect(loc);
 
-                        writeln!(w, "        // init: {:?}", init.get())?;
-                        writeln!(w, "        // live: {:?}", live.get())?;
-                    }
-                    PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
-                        let loc = body.terminator_loc(bb);
-                        init.seek_after_primary_effect(loc);
-                        live.seek_before_primary_effect(loc);
+                    writeln!(w, "        // init: {:?}", init.get())?;
+                    writeln!(w, "        // live: {:?}", live.get())?;
+                }
+                PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
+                    let loc = body.terminator_loc(bb);
+                    init.seek_after_primary_effect(loc);
+                    live.seek_before_primary_effect(loc);
 
-                        writeln!(w, "        // init: {:?}", init.get())?;
-                        writeln!(w, "        // live: {:?}", live.get())?;
-                    }
-
-                    PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
-                        init.seek_to_block_start(bb);
-                        live.seek_to_block_start(bb);
-
-                        writeln!(w, "    // init: {:?}", init.get())?;
-                        writeln!(w, "    // live: {:?}", live.get())?;
-                    }
-
-                    PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
-
-                    PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
-                        writeln!(w, "        // init: <unreachable>")?;
-                        writeln!(w, "        // live: <unreachable>")?;
-                    }
-
-                    PassWhere::BeforeBlock(_) => {
-                        writeln!(w, "    // init: <unreachable>")?;
-                        writeln!(w, "    // live: <unreachable>")?;
-                    }
+                    writeln!(w, "        // init: {:?}", init.get())?;
+                    writeln!(w, "        // live: {:?}", live.get())?;
                 }
 
-                Ok(())
-            },
-        );
+                PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
+                    init.seek_to_block_start(bb);
+                    live.seek_to_block_start(bb);
+
+                    writeln!(w, "    // init: {:?}", init.get())?;
+                    writeln!(w, "    // live: {:?}", live.get())?;
+                }
+
+                PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
+
+                PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
+                    writeln!(w, "        // init: <unreachable>")?;
+                    writeln!(w, "        // live: <unreachable>")?;
+                }
+
+                PassWhere::BeforeBlock(_) => {
+                    writeln!(w, "    // init: <unreachable>")?;
+                    writeln!(w, "    // live: <unreachable>")?;
+                }
+            }
+
+            Ok(())
+        });
 
         let mut this = Self {
             relevant_locals,
diff --git a/compiler/rustc_mir/src/transform/dump_mir.rs b/compiler/rustc_mir/src/transform/dump_mir.rs
index 5ce6f4f..5b6edf1 100644
--- a/compiler/rustc_mir/src/transform/dump_mir.rs
+++ b/compiler/rustc_mir/src/transform/dump_mir.rs
@@ -5,7 +5,7 @@
 use std::fs::File;
 use std::io;
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util as mir_util;
 use rustc_middle::mir::Body;
 use rustc_middle::ty::TyCtxt;
@@ -18,7 +18,7 @@
         Cow::Borrowed(self.0)
     }
 
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut Body<'tcx>) {}
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
 }
 
 pub struct Disambiguator {
@@ -36,17 +36,15 @@
     tcx: TyCtxt<'tcx>,
     pass_num: &dyn fmt::Display,
     pass_name: &str,
-    source: MirSource<'tcx>,
     body: &Body<'tcx>,
     is_after: bool,
 ) {
-    if mir_util::dump_enabled(tcx, pass_name, source.def_id()) {
+    if mir_util::dump_enabled(tcx, pass_name, body.source.def_id()) {
         mir_util::dump_mir(
             tcx,
             Some(pass_num),
             pass_name,
             &Disambiguator { is_after },
-            source,
             body,
             |_, _| Ok(()),
         );
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
index 67e679a..f97dcf4 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
@@ -1,10 +1,7 @@
-use crate::{
-    transform::{MirPass, MirSource},
-    util::patch::MirPatch,
-};
+use crate::{transform::MirPass, util::patch::MirPatch};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{Ty, TyCtxt};
-use std::{borrow::Cow, fmt::Debug};
+use std::fmt::Debug;
 
 use super::simplify::simplify_cfg;
 
@@ -28,11 +25,11 @@
 pub struct EarlyOtherwiseBranch;
 
 impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.opts.debugging_opts.mir_opt_level < 1 {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        if tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
             return;
         }
-        trace!("running EarlyOtherwiseBranch on {:?}", source);
+        trace!("running EarlyOtherwiseBranch on {:?}", body.source);
         // we are only interested in this bb if the terminator is a switchInt
         let bbs_with_switch =
             body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));
@@ -91,22 +88,24 @@
             let not_equal_rvalue = Rvalue::BinaryOp(
                 not_equal,
                 Operand::Copy(Place::from(second_discriminant_temp)),
-                Operand::Copy(Place::from(first_descriminant_place)),
+                Operand::Copy(first_descriminant_place),
             );
             patch.add_statement(
                 end_of_block_location,
                 StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)),
             );
 
-            let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply
+            let new_targets = opt_to_apply
                 .infos
                 .iter()
                 .flat_map(|x| x.second_switch_info.targets_with_values.iter())
-                .cloned()
-                .unzip();
+                .cloned();
 
-            // add otherwise case in the end
-            targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb);
+            let targets = SwitchTargets::new(
+                new_targets,
+                opt_to_apply.infos[0].first_switch_info.otherwise_bb,
+            );
+
             // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
             let new_switch_data = BasicBlockData::new(Some(Terminator {
                 source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
@@ -114,8 +113,7 @@
                     // the first and second discriminants are equal, so just pick one
                     discr: Operand::Copy(first_descriminant_place),
                     switch_ty: discr_type,
-                    values: Cow::from(values_to_jump_to),
-                    targets: targets_to_jump_to,
+                    targets,
                 },
             }));
 
@@ -179,7 +177,7 @@
     /// The basic block that the otherwise branch points to
     otherwise_bb: BasicBlock,
     /// Target along with the value being branched from. Otherwise is not included
-    targets_with_values: Vec<(BasicBlock, u128)>,
+    targets_with_values: Vec<(u128, BasicBlock)>,
     discr_source_info: SourceInfo,
     /// The place of the discriminant used in the switch
     discr_used_in_switch: Place<'tcx>,
@@ -214,7 +212,7 @@
         let discr = self.find_switch_discriminant_info(bb, switch)?;
 
         // go through each target, finding a discriminant read, and a switch
-        let results = discr.targets_with_values.iter().map(|(target, value)| {
+        let results = discr.targets_with_values.iter().map(|(value, target)| {
             self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone())
         });
 
@@ -256,7 +254,7 @@
             }
 
             // check that the value being matched on is the same. The
-            if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() {
+            if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() {
                 trace!("NO: values being matched on are not the same");
                 return None;
             }
@@ -273,7 +271,7 @@
             //  ```
             // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
             if !(this_bb_discr_info.targets_with_values.len() == 1
-                && this_bb_discr_info.targets_with_values[0].1 == value)
+                && this_bb_discr_info.targets_with_values[0].0 == value)
             {
                 trace!(
                     "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
@@ -299,18 +297,14 @@
         switch: &Terminator<'tcx>,
     ) -> Option<SwitchDiscriminantInfo<'tcx>> {
         match &switch.kind {
-            TerminatorKind::SwitchInt { discr, targets, values, .. } => {
+            TerminatorKind::SwitchInt { discr, targets, .. } => {
                 let discr_local = discr.place()?.as_local()?;
                 // the declaration of the discriminant read. Place of this read is being used in the switch
                 let discr_decl = &self.body.local_decls()[discr_local];
                 let discr_ty = discr_decl.ty;
                 // the otherwise target lies as the last element
-                let otherwise_bb = targets.get(values.len())?.clone();
-                let targets_with_values = targets
-                    .iter()
-                    .zip(values.iter())
-                    .map(|(t, v)| (t.clone(), v.clone()))
-                    .collect();
+                let otherwise_bb = targets.otherwise();
+                let targets_with_values = targets.iter().collect();
 
                 // find the place of the adt where the discriminant is being read from
                 // assume this is the last statement of the block
diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs
index a8b2ee5..3d435f6 100644
--- a/compiler/rustc_mir/src/transform/elaborate_drops.rs
+++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs
@@ -5,12 +5,11 @@
 use crate::dataflow::MoveDataParamEnv;
 use crate::dataflow::{on_all_children_bits, on_all_drop_children_bits};
 use crate::dataflow::{Analysis, ResultsCursor};
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util::elaborate_drops::{elaborate_drop, DropFlagState, Unwind};
 use crate::util::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle};
 use crate::util::patch::MirPatch;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
@@ -21,11 +20,11 @@
 pub struct ElaborateDrops;
 
 impl<'tcx> MirPass<'tcx> for ElaborateDrops {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        debug!("elaborate_drops({:?} @ {:?})", src, body.span);
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
 
-        let def_id = src.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(src.def_id());
+        let def_id = body.source.def_id();
+        let param_env = tcx.param_env_reveal_all_normalized(def_id);
         let move_data = match MoveData::gather_moves(body, tcx, param_env) {
             Ok(move_data) => move_data,
             Err((move_data, _)) => {
@@ -39,10 +38,10 @@
         let elaborate_patch = {
             let body = &*body;
             let env = MoveDataParamEnv { move_data, param_env };
-            let dead_unwinds = find_dead_unwinds(tcx, body, def_id, &env);
+            let dead_unwinds = find_dead_unwinds(tcx, body, &env);
 
             let inits = MaybeInitializedPlaces::new(tcx, body, &env)
-                .into_engine(tcx, body, def_id)
+                .into_engine(tcx, body)
                 .dead_unwinds(&dead_unwinds)
                 .pass_name("elaborate_drops")
                 .iterate_to_fixpoint()
@@ -50,7 +49,7 @@
 
             let uninits = MaybeUninitializedPlaces::new(tcx, body, &env)
                 .mark_inactive_variants_as_uninit()
-                .into_engine(tcx, body, def_id)
+                .into_engine(tcx, body)
                 .dead_unwinds(&dead_unwinds)
                 .pass_name("elaborate_drops")
                 .iterate_to_fixpoint()
@@ -76,7 +75,6 @@
 fn find_dead_unwinds<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    def_id: hir::def_id::DefId,
     env: &MoveDataParamEnv<'tcx>,
 ) -> BitSet<BasicBlock> {
     debug!("find_dead_unwinds({:?})", body.span);
@@ -84,7 +82,7 @@
     // reach cleanup blocks, which can't have unwind edges themselves.
     let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env)
-        .into_engine(tcx, body, def_id)
+        .into_engine(tcx, body)
         .pass_name("find_dead_unwinds")
         .iterate_to_fixpoint()
         .into_results_cursor(body);
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index 1fffcf8..039d475 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -55,13 +55,12 @@
 use crate::dataflow::{self, Analysis};
 use crate::transform::no_landing_pads::no_landing_pads;
 use crate::transform::simplify;
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util::dump_mir;
 use crate::util::expand_aggregate;
 use crate::util::storage;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::{BitMatrix, BitSet};
 use rustc_index::vec::{Idx, IndexVec};
@@ -72,7 +71,6 @@
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::PanicStrategy;
-use std::borrow::Cow;
 use std::{iter, ops};
 
 pub struct StateTransform;
@@ -451,24 +449,22 @@
 fn locals_live_across_suspend_points(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    source: MirSource<'tcx>,
     always_live_locals: &storage::AlwaysLiveLocals,
     movable: bool,
 ) -> LivenessInfo {
-    let def_id = source.def_id();
     let body_ref: &Body<'_> = &body;
 
     // Calculate when MIR locals have live storage. This gives us an upper bound of their
     // lifetimes.
     let mut storage_live = MaybeStorageLive::new(always_live_locals.clone())
-        .into_engine(tcx, body_ref, def_id)
+        .into_engine(tcx, body_ref)
         .iterate_to_fixpoint()
         .into_results_cursor(body_ref);
 
     // Calculate the MIR locals which have been previously
     // borrowed (even if they are still active).
     let borrowed_locals_results = MaybeBorrowedLocals::all_borrows()
-        .into_engine(tcx, body_ref, def_id)
+        .into_engine(tcx, body_ref)
         .pass_name("generator")
         .iterate_to_fixpoint();
 
@@ -478,14 +474,14 @@
     // Calculate the MIR locals that we actually need to keep storage around
     // for.
     let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
-        .into_engine(tcx, body_ref, def_id)
+        .into_engine(tcx, body_ref)
         .iterate_to_fixpoint();
     let mut requires_storage_cursor =
         dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
 
     // Calculate the liveness of MIR locals ignoring borrows.
     let mut liveness = MaybeLiveLocals
-        .into_engine(tcx, body_ref, def_id)
+        .into_engine(tcx, body_ref)
         .pass_name("generator")
         .iterate_to_fixpoint()
         .into_results_cursor(body_ref);
@@ -723,11 +719,11 @@
 fn sanitize_witness<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    did: DefId,
     witness: Ty<'tcx>,
     upvars: &Vec<Ty<'tcx>>,
     saved_locals: &GeneratorSavedLocals,
 ) {
+    let did = body.source.def_id();
     let allowed_upvars = tcx.erase_regions(upvars);
     let allowed = match witness.kind() {
         ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s),
@@ -842,11 +838,12 @@
 ) {
     let default_block = insert_term_block(body, default);
     let (assign, discr) = transform.get_discr(body);
+    let switch_targets =
+        SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
     let switch = TerminatorKind::SwitchInt {
         discr: Operand::Move(discr),
         switch_ty: transform.discr_ty,
-        values: Cow::from(cases.iter().map(|&(i, _)| i as u128).collect::<Vec<_>>()),
-        targets: cases.iter().map(|&(_, d)| d).chain(iter::once(default_block)).collect(),
+        targets: switch_targets,
     };
 
     let source_info = SourceInfo::outermost(body.span);
@@ -866,7 +863,7 @@
     }
 }
 
-fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut Body<'tcx>) {
+fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     use crate::shim::DropShimElaborator;
     use crate::util::elaborate_drops::{elaborate_drop, Unwind};
     use crate::util::patch::MirPatch;
@@ -875,6 +872,7 @@
     // this is ok because `open_drop` can only be reached within that own
     // generator's resume function.
 
+    let def_id = body.source.def_id();
     let param_env = tcx.param_env(def_id);
 
     let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env };
@@ -915,7 +913,6 @@
 fn create_generator_drop_shim<'tcx>(
     tcx: TyCtxt<'tcx>,
     transform: &TransformVisitor<'tcx>,
-    source: MirSource<'tcx>,
     gen_ty: Ty<'tcx>,
     body: &mut Body<'tcx>,
     drop_clean: BasicBlock,
@@ -968,7 +965,7 @@
     // unrelated code from the resume part of the function
     simplify::remove_dead_blocks(&mut body);
 
-    dump_mir(tcx, None, "generator_drop", &0, source, &body, |_, _| Ok(()));
+    dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
 
     body
 }
@@ -1070,7 +1067,6 @@
 fn create_generator_resume_function<'tcx>(
     tcx: TyCtxt<'tcx>,
     transform: TransformVisitor<'tcx>,
-    source: MirSource<'tcx>,
     body: &mut Body<'tcx>,
     can_return: bool,
 ) {
@@ -1142,7 +1138,7 @@
     // unrelated code from the drop part of the function
     simplify::remove_dead_blocks(body);
 
-    dump_mir(tcx, None, "generator_resume", &0, source, body, |_, _| Ok(()));
+    dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
 }
 
 fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
@@ -1239,7 +1235,7 @@
 }
 
 impl<'tcx> MirPass<'tcx> for StateTransform {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let yield_ty = if let Some(yield_ty) = body.yield_ty {
             yield_ty
         } else {
@@ -1249,8 +1245,6 @@
 
         assert!(body.generator_drop.is_none());
 
-        let def_id = source.def_id();
-
         // The first argument is the generator type passed by value
         let gen_ty = body.local_decls.raw[1].ty;
 
@@ -1307,9 +1301,9 @@
         let always_live_locals = storage::AlwaysLiveLocals::new(&body);
 
         let liveness_info =
-            locals_live_across_suspend_points(tcx, body, source, &always_live_locals, movable);
+            locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
 
-        sanitize_witness(tcx, body, def_id, interior, &upvars, &liveness_info.saved_locals);
+        sanitize_witness(tcx, body, interior, &upvars, &liveness_info.saved_locals);
 
         if tcx.sess.opts.debugging_opts.validate_mir {
             let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
@@ -1356,23 +1350,22 @@
         // This is expanded to a drop ladder in `elaborate_generator_drops`.
         let drop_clean = insert_clean_drop(body);
 
-        dump_mir(tcx, None, "generator_pre-elab", &0, source, body, |_, _| Ok(()));
+        dump_mir(tcx, None, "generator_pre-elab", &0, body, |_, _| Ok(()));
 
         // Expand `drop(generator_struct)` to a drop ladder which destroys upvars.
         // If any upvars are moved out of, drop elaboration will handle upvar destruction.
         // However we need to also elaborate the code generated by `insert_clean_drop`.
-        elaborate_generator_drops(tcx, def_id, body);
+        elaborate_generator_drops(tcx, body);
 
-        dump_mir(tcx, None, "generator_post-transform", &0, source, body, |_, _| Ok(()));
+        dump_mir(tcx, None, "generator_post-transform", &0, body, |_, _| Ok(()));
 
         // Create a copy of our MIR and use it to create the drop shim for the generator
-        let drop_shim =
-            create_generator_drop_shim(tcx, &transform, source, gen_ty, body, drop_clean);
+        let drop_shim = create_generator_drop_shim(tcx, &transform, gen_ty, body, drop_clean);
 
         body.generator_drop = Some(box drop_shim);
 
         // Create the Generator::resume function
-        create_generator_resume_function(tcx, transform, source, body, can_return);
+        create_generator_resume_function(tcx, transform, body, can_return);
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index 4e7cacc..796ad6c 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -12,7 +12,7 @@
 use rustc_target::spec::abi::Abi;
 
 use super::simplify::{remove_dead_blocks, CfgSimplifier};
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use std::collections::VecDeque;
 use std::iter;
 
@@ -37,7 +37,7 @@
 }
 
 impl<'tcx> MirPass<'tcx> for Inline {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
             if tcx.sess.opts.debugging_opts.instrument_coverage {
                 // The current implementation of source code coverage injects code region counters
@@ -45,8 +45,12 @@
                 // based function.
                 debug!("function inlining is disabled when compiling with `instrument_coverage`");
             } else {
-                Inliner { tcx, source, codegen_fn_attrs: tcx.codegen_fn_attrs(source.def_id()) }
-                    .run_pass(body);
+                Inliner {
+                    tcx,
+                    param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
+                    codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
+                }
+                .run_pass(body);
             }
         }
     }
@@ -54,7 +58,7 @@
 
 struct Inliner<'tcx> {
     tcx: TyCtxt<'tcx>,
-    source: MirSource<'tcx>,
+    param_env: ParamEnv<'tcx>,
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
 }
 
@@ -74,15 +78,15 @@
 
         let mut callsites = VecDeque::new();
 
-        let param_env = self.tcx.param_env_reveal_all_normalized(self.source.def_id());
+        let def_id = caller_body.source.def_id();
 
         // Only do inlining into fn bodies.
-        let id = self.tcx.hir().local_def_id_to_hir_id(self.source.def_id().expect_local());
-        if self.tcx.hir().body_owner_kind(id).is_fn_or_closure() && self.source.promoted.is_none() {
+        let self_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        if self.tcx.hir().body_owner_kind(self_hir_id).is_fn_or_closure()
+            && caller_body.source.promoted.is_none()
+        {
             for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated() {
-                if let Some(callsite) =
-                    self.get_valid_function_call(bb, bb_data, caller_body, param_env)
-                {
+                if let Some(callsite) = self.get_valid_function_call(bb, bb_data, caller_body) {
                     callsites.push_back(callsite);
                 }
             }
@@ -104,8 +108,6 @@
 
                 let callee_body = if let Some(callee_def_id) = callsite.callee.as_local() {
                     let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
-                    let self_hir_id =
-                        self.tcx.hir().local_def_id_to_hir_id(self.source.def_id().expect_local());
                     // Avoid a cycle here by only using `optimized_mir` only if we have
                     // a lower `HirId` than the callee. This ensures that the callee will
                     // not inline us. This trick only works without incremental compilation.
@@ -130,7 +132,7 @@
                 let callee_body = if self.consider_optimizing(callsite, callee_body) {
                     self.tcx.subst_and_normalize_erasing_regions(
                         &callsite.substs,
-                        param_env,
+                        self.param_env,
                         callee_body,
                     )
                 } else {
@@ -158,7 +160,7 @@
                 // Add callsites from inlined function
                 for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated().skip(start) {
                     if let Some(new_callsite) =
-                        self.get_valid_function_call(bb, bb_data, caller_body, param_env)
+                        self.get_valid_function_call(bb, bb_data, caller_body)
                     {
                         // Don't inline the same function multiple times.
                         if callsite.callee != new_callsite.callee {
@@ -178,7 +180,7 @@
 
         // Simplify if we inlined anything.
         if changed {
-            debug!("running simplify cfg on {:?}", self.source);
+            debug!("running simplify cfg on {:?}", caller_body.source);
             CfgSimplifier::new(caller_body).simplify();
             remove_dead_blocks(caller_body);
         }
@@ -189,7 +191,6 @@
         bb: BasicBlock,
         bb_data: &BasicBlockData<'tcx>,
         caller_body: &Body<'tcx>,
-        param_env: ParamEnv<'tcx>,
     ) -> Option<CallSite<'tcx>> {
         // Don't inline calls that are in cleanup blocks.
         if bb_data.is_cleanup {
@@ -200,8 +201,13 @@
         let terminator = bb_data.terminator();
         if let TerminatorKind::Call { func: ref op, .. } = terminator.kind {
             if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() {
+                // To resolve an instance its substs have to be fully normalized, so
+                // we do this here.
+                let normalized_substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
                 let instance =
-                    Instance::resolve(self.tcx, param_env, callee_def_id, substs).ok().flatten()?;
+                    Instance::resolve(self.tcx, self.param_env, callee_def_id, normalized_substs)
+                        .ok()
+                        .flatten()?;
 
                 if let InstanceDef::Virtual(..) = instance.def {
                     return None;
@@ -299,9 +305,6 @@
         debug!("    final inline threshold = {}", threshold);
 
         // FIXME: Give a bonus to functions with only a single caller
-
-        let param_env = tcx.param_env(self.source.def_id());
-
         let mut first_block = true;
         let mut cost = 0;
 
@@ -334,7 +337,7 @@
                     // If the place doesn't actually need dropping, treat it like
                     // a regular goto.
                     let ty = place.ty(callee_body, tcx).subst(tcx, callsite.substs).ty;
-                    if ty.needs_drop(tcx, param_env) {
+                    if ty.needs_drop(tcx, self.param_env) {
                         cost += CALL_PENALTY;
                         if let Some(unwind) = unwind {
                             cost += LANDINGPAD_PENALTY;
@@ -399,7 +402,7 @@
             let ty = v.ty.subst(tcx, callsite.substs);
             // Cost of the var is the size in machine-words, if we know
             // it.
-            if let Some(size) = type_size_of(tcx, param_env, ty) {
+            if let Some(size) = type_size_of(tcx, self.param_env, ty) {
                 cost += (size / ptr_size) as usize;
             } else {
                 cost += UNKNOWN_SIZE_COST;
@@ -430,7 +433,7 @@
         match terminator.kind {
             // FIXME: Handle inlining of diverging calls
             TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
-                debug!("inlined {:?} into {:?}", callsite.callee, self.source);
+                debug!("inlined {:?} into {:?}", callsite.callee, caller_body.source);
 
                 let mut local_map = IndexVec::with_capacity(callee_body.local_decls.len());
                 let mut scope_map = IndexVec::with_capacity(callee_body.source_scopes.len());
@@ -772,7 +775,7 @@
                 *target = self.update_target(*target);
             }
             TerminatorKind::SwitchInt { ref mut targets, .. } => {
-                for tgt in targets {
+                for tgt in targets.all_targets_mut() {
                     *tgt = self.update_target(*tgt);
                 }
             }
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
index 3ed0aea..c0b3d5f 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir/src/transform/instcombine.rs
@@ -1,6 +1,6 @@
 //! Performs various peephole optimizations.
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::Mutability;
 use rustc_index::vec::Idx;
@@ -19,7 +19,7 @@
 pub struct InstCombine;
 
 impl<'tcx> MirPass<'tcx> for InstCombine {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
         // read-only so that we can do global analyses on the MIR in the process (e.g.
         // `Place::ty()`).
@@ -119,6 +119,11 @@
     }
 
     fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> {
+        // FIXME(#78192): This optimization can result in unsoundness.
+        if !self.tcx.sess.opts.debugging_opts.unsound_mir_opts {
+            return None;
+        }
+
         // Look for the sequence
         //
         // _2 = &_1;
diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs
index a5b30a2..6824c73 100644
--- a/compiler/rustc_mir/src/transform/instrument_coverage.rs
+++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs
@@ -1,26 +1,32 @@
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util::pretty;
-use crate::util::spanview::{
-    source_range_no_file, statement_kind_name, terminator_kind_name, write_spanview_document,
-    SpanViewable, TOOLTIP_INDENT,
-};
+use crate::util::spanview::{self, SpanViewable};
 
 use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
 use rustc_index::bit_set::BitSet;
+use rustc_index::vec::IndexVec;
 use rustc_middle::hir;
+use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::ich::StableHashingContext;
 use rustc_middle::mir;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{
-    BasicBlock, BasicBlockData, Coverage, CoverageInfo, Location, Statement, StatementKind,
-    TerminatorKind,
+    AggregateKind, BasicBlock, BasicBlockData, Coverage, CoverageInfo, FakeReadCause, Location,
+    Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
-use rustc_span::{FileName, Pos, RealFileName, Span, Symbol};
+use rustc_span::source_map::original_sp;
+use rustc_span::{BytePos, CharPos, Pos, SourceFile, Span, Symbol, SyntaxContext};
+
+use std::cmp::Ordering;
+
+const ID_SEPARATOR: &str = ",";
 
 /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
 /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
@@ -33,6 +39,21 @@
     providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id);
 }
 
+/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in
+/// other words, the number of counter value references injected into the MIR (plus 1 for the
+/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected
+/// counters have a counter ID from `1..num_counters-1`.
+///
+/// `num_expressions` is the number of counter expressions added to the MIR body.
+///
+/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend
+/// code generate, to lookup counters and expressions by simple u32 indexes.
+///
+/// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code
+/// including injected counters. (It is OK if some counters are optimized out, but those counters
+/// are still included in the total `num_counters` or `num_expressions`.) Simply counting the
+/// calls may not work; but computing the number of counters or expressions by adding `1` to the
+/// highest ID (for a given instrumented function) is valid.
 struct CoverageVisitor {
     info: CoverageInfo,
 }
@@ -57,15 +78,6 @@
 fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo {
     let mir_body = tcx.optimized_mir(def_id);
 
-    // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected
-    // counters, with each counter having a counter ID from `0..num_counters-1`. MIR optimization
-    // may split and duplicate some BasicBlock sequences. Simply counting the calls may not
-    // work; but computing the num_counters by adding `1` to the highest counter_id (for a given
-    // instrumented function) is valid.
-    //
-    // `num_expressions` is the number of counter expressions added to the MIR body. Both
-    // `num_counters` and `num_expressions` are used to initialize new vectors, during backend
-    // code generate, to lookup counters and expressions by simple u32 indexes.
     let mut coverage_visitor =
         CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } };
 
@@ -74,62 +86,426 @@
 }
 
 impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
-    fn run_pass(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        mir_source: MirSource<'tcx>,
-        mir_body: &mut mir::Body<'tcx>,
-    ) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
         // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
         // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
-        if mir_source.promoted.is_none() {
-            Instrumentor::new(&self.name(), tcx, mir_source, mir_body).inject_counters();
+        if mir_body.source.promoted.is_some() {
+            trace!(
+                "InstrumentCoverage skipped for {:?} (already promoted for Miri evaluation)",
+                mir_body.source.def_id()
+            );
+            return;
+        }
+
+        let hir_id = tcx.hir().local_def_id_to_hir_id(mir_body.source.def_id().expect_local());
+        let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+
+        // Only instrument functions, methods, and closures (not constants since they are evaluated
+        // at compile time by Miri).
+        // FIXME(#73156): Handle source code coverage in const eval
+        if !is_fn_like {
+            trace!(
+                "InstrumentCoverage skipped for {:?} (not an FnLikeNode)",
+                mir_body.source.def_id(),
+            );
+            return;
+        }
+        // FIXME(richkadel): By comparison, the MIR pass `ConstProp` includes associated constants,
+        // with functions, methods, and closures. I assume Miri is used for associated constants as
+        // well. If not, we may need to include them here too.
+
+        trace!("InstrumentCoverage starting for {:?}", mir_body.source.def_id());
+        Instrumentor::new(&self.name(), tcx, mir_body).inject_counters();
+        trace!("InstrumentCoverage starting for {:?}", mir_body.source.def_id());
+    }
+}
+
+/// A BasicCoverageBlock (BCB) represents the maximal-length sequence of CFG (MIR) BasicBlocks
+/// without conditional branches.
+///
+/// The BCB allows coverage analysis to be performed on a simplified projection of the underlying
+/// MIR CFG, without altering the original CFG. Note that running the MIR `SimplifyCfg` transform,
+/// is not sufficient, and therefore not necessary, since the BCB-based CFG projection is a more
+/// aggressive simplification. For example:
+///
+///   * The BCB CFG projection ignores (trims) branches not relevant to coverage, such as unwind-
+///     related code that is injected by the Rust compiler but has no physical source code to
+///     count. This also means a BasicBlock with a `Call` terminator can be merged into its
+///     primary successor target block, in the same BCB.
+///   * Some BasicBlock terminators support Rust-specific concerns--like borrow-checking--that are
+///     not relevant to coverage analysis. `FalseUnwind`, for example, can be treated the same as
+///     a `Goto`, and merged with its successor into the same BCB.
+///
+/// Each BCB with at least one computed `CoverageSpan` will have no more than one `Counter`.
+/// In some cases, a BCB's execution count can be computed by `CounterExpression`. Additional
+/// disjoint `CoverageSpan`s in a BCB can also be counted by `CounterExpression` (by adding `ZERO`
+/// to the BCB's primary counter or expression).
+///
+/// Dominator/dominated relationships (which are fundamental to the coverage analysis algorithm)
+/// between two BCBs can be computed using the `mir::Body` `dominators()` with any `BasicBlock`
+/// member of each BCB. (For consistency, BCB's use the first `BasicBlock`, also referred to as the
+/// `bcb_leader_bb`.)
+///
+/// The BCB CFG projection is critical to simplifying the coverage analysis by ensuring graph
+/// path-based queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch
+/// (control flow) significance.
+#[derive(Debug, Clone)]
+struct BasicCoverageBlock {
+    pub blocks: Vec<BasicBlock>,
+}
+
+impl BasicCoverageBlock {
+    pub fn leader_bb(&self) -> BasicBlock {
+        self.blocks[0]
+    }
+
+    pub fn id(&self) -> String {
+        format!(
+            "@{}",
+            self.blocks
+                .iter()
+                .map(|bb| bb.index().to_string())
+                .collect::<Vec<_>>()
+                .join(ID_SEPARATOR)
+        )
+    }
+}
+
+struct BasicCoverageBlocks {
+    vec: IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
+}
+
+impl BasicCoverageBlocks {
+    pub fn from_mir(mir_body: &mir::Body<'tcx>) -> Self {
+        let mut basic_coverage_blocks =
+            BasicCoverageBlocks { vec: IndexVec::from_elem_n(None, mir_body.basic_blocks().len()) };
+        basic_coverage_blocks.extract_from_mir(mir_body);
+        basic_coverage_blocks
+    }
+
+    pub fn iter(&self) -> impl Iterator<Item = &BasicCoverageBlock> {
+        self.vec.iter().filter_map(|option| option.as_ref())
+    }
+
+    fn extract_from_mir(&mut self, mir_body: &mir::Body<'tcx>) {
+        // Traverse the CFG but ignore anything following an `unwind`
+        let cfg_without_unwind = ShortCircuitPreorder::new(mir_body, |term_kind| {
+            let mut successors = term_kind.successors();
+            match &term_kind {
+                // SwitchInt successors are never unwind, and all of them should be traversed.
+
+                // NOTE: TerminatorKind::FalseEdge targets from SwitchInt don't appear to be
+                // helpful in identifying unreachable code. I did test the theory, but the following
+                // changes were not beneficial. (I assumed that replacing some constants with
+                // non-deterministic variables might effect which blocks were targeted by a
+                // `FalseEdge` `imaginary_target`. It did not.)
+                //
+                // Also note that, if there is a way to identify BasicBlocks that are part of the
+                // MIR CFG, but not actually reachable, here are some other things to consider:
+                //
+                // Injecting unreachable code regions will probably require computing the set
+                // difference between the basic blocks found without filtering out unreachable
+                // blocks, and the basic blocks found with the filter; then computing the
+                // `CoverageSpans` without the filter; and then injecting `Counter`s or
+                // `CounterExpression`s for blocks that are not unreachable, or injecting
+                // `Unreachable` code regions otherwise. This seems straightforward, but not
+                // trivial.
+                //
+                // Alternatively, we might instead want to leave the unreachable blocks in
+                // (bypass the filter here), and inject the counters. This will result in counter
+                // values of zero (0) for unreachable code (and, notably, the code will be displayed
+                // with a red background by `llvm-cov show`).
+                //
+                // TerminatorKind::SwitchInt { .. } => {
+                //     let some_imaginary_target = successors.clone().find_map(|&successor| {
+                //         let term = mir_body.basic_blocks()[successor].terminator();
+                //         if let TerminatorKind::FalseEdge { imaginary_target, .. } = term.kind {
+                //             if mir_body.predecessors()[imaginary_target].len() == 1 {
+                //                 return Some(imaginary_target);
+                //             }
+                //         }
+                //         None
+                //     });
+                //     if let Some(imaginary_target) = some_imaginary_target {
+                //         box successors.filter(move |&&successor| successor != imaginary_target)
+                //     } else {
+                //         box successors
+                //     }
+                // }
+                //
+                // Note this also required changing the closure signature for the
+                // `ShortCurcuitPreorder` to:
+                //
+                // F: Fn(&'tcx TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = &BasicBlock> + 'a>,
+                TerminatorKind::SwitchInt { .. } => successors,
+
+                // For all other kinds, return only the first successor, if any, and ignore unwinds
+                _ => successors.next().into_iter().chain(&[]),
+            }
+        });
+
+        // Walk the CFG using a Preorder traversal, which starts from `START_BLOCK` and follows
+        // each block terminator's `successors()`. Coverage spans must map to actual source code,
+        // so compiler generated blocks and paths can be ignored. To that end the CFG traversal
+        // intentionally omits unwind paths.
+        let mut blocks = Vec::new();
+        for (bb, data) in cfg_without_unwind {
+            if let Some(last) = blocks.last() {
+                let predecessors = &mir_body.predecessors()[bb];
+                if predecessors.len() > 1 || !predecessors.contains(last) {
+                    // The `bb` has more than one _incoming_ edge, and should start its own
+                    // `BasicCoverageBlock`. (Note, the `blocks` vector does not yet include `bb`;
+                    // it contains a sequence of one or more sequential blocks with no intermediate
+                    // branches in or out. Save these as a new `BasicCoverageBlock` before starting
+                    // the new one.)
+                    self.add_basic_coverage_block(blocks.split_off(0));
+                    debug!(
+                        "  because {}",
+                        if predecessors.len() > 1 {
+                            "predecessors.len() > 1".to_owned()
+                        } else {
+                            format!("bb {} is not in precessors: {:?}", bb.index(), predecessors)
+                        }
+                    );
+                }
+            }
+            blocks.push(bb);
+
+            let term = data.terminator();
+
+            match term.kind {
+                TerminatorKind::Return { .. }
+                | TerminatorKind::Abort
+                | TerminatorKind::Assert { .. }
+                | TerminatorKind::Yield { .. }
+                | TerminatorKind::SwitchInt { .. } => {
+                    // The `bb` has more than one _outgoing_ edge, or exits the function. Save the
+                    // current sequence of `blocks` gathered to this point, as a new
+                    // `BasicCoverageBlock`.
+                    self.add_basic_coverage_block(blocks.split_off(0));
+                    debug!("  because term.kind = {:?}", term.kind);
+                    // Note that this condition is based on `TerminatorKind`, even though it
+                    // theoretically boils down to `successors().len() != 1`; that is, either zero
+                    // (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but
+                    // since the Coverage graph (the BCB CFG projection) ignores things like unwind
+                    // branches (which exist in the `Terminator`s `successors()` list) checking the
+                    // number of successors won't work.
+                }
+                TerminatorKind::Goto { .. }
+                | TerminatorKind::Resume
+                | TerminatorKind::Unreachable
+                | TerminatorKind::Drop { .. }
+                | TerminatorKind::DropAndReplace { .. }
+                | TerminatorKind::Call { .. }
+                | TerminatorKind::GeneratorDrop
+                | TerminatorKind::FalseEdge { .. }
+                | TerminatorKind::FalseUnwind { .. }
+                | TerminatorKind::InlineAsm { .. } => {}
+            }
+        }
+
+        if !blocks.is_empty() {
+            // process any remaining blocks into a final `BasicCoverageBlock`
+            self.add_basic_coverage_block(blocks.split_off(0));
+            debug!("  because the end of the CFG was reached while traversing");
+        }
+    }
+
+    fn add_basic_coverage_block(&mut self, blocks: Vec<BasicBlock>) {
+        let leader_bb = blocks[0];
+        let bcb = BasicCoverageBlock { blocks };
+        debug!("adding BCB: {:?}", bcb);
+        self.vec[leader_bb] = Some(bcb);
+    }
+}
+
+impl std::ops::Index<BasicBlock> for BasicCoverageBlocks {
+    type Output = BasicCoverageBlock;
+
+    fn index(&self, index: BasicBlock) -> &Self::Output {
+        self.vec[index].as_ref().expect("is_some if BasicBlock is a BasicCoverageBlock leader")
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+enum CoverageStatement {
+    Statement(BasicBlock, Span, usize),
+    Terminator(BasicBlock, Span),
+}
+
+impl CoverageStatement {
+    pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String {
+        match *self {
+            Self::Statement(bb, span, stmt_index) => {
+                let stmt = &mir_body.basic_blocks()[bb].statements[stmt_index];
+                format!(
+                    "{}: @{}[{}]: {:?}",
+                    spanview::source_range_no_file(tcx, &span),
+                    bb.index(),
+                    stmt_index,
+                    stmt
+                )
+            }
+            Self::Terminator(bb, span) => {
+                let term = mir_body.basic_blocks()[bb].terminator();
+                format!(
+                    "{}: @{}.{}: {:?}",
+                    spanview::source_range_no_file(tcx, &span),
+                    bb.index(),
+                    term_type(&term.kind),
+                    term.kind
+                )
+            }
+        }
+    }
+
+    pub fn span(&self) -> &Span {
+        match self {
+            Self::Statement(_, span, _) | Self::Terminator(_, span) => span,
         }
     }
 }
 
-#[derive(Clone)]
-struct CoverageRegion {
-    pub span: Span,
-    pub blocks: Vec<BasicBlock>,
+fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str {
+    match kind {
+        TerminatorKind::Goto { .. } => "Goto",
+        TerminatorKind::SwitchInt { .. } => "SwitchInt",
+        TerminatorKind::Resume => "Resume",
+        TerminatorKind::Abort => "Abort",
+        TerminatorKind::Return => "Return",
+        TerminatorKind::Unreachable => "Unreachable",
+        TerminatorKind::Drop { .. } => "Drop",
+        TerminatorKind::DropAndReplace { .. } => "DropAndReplace",
+        TerminatorKind::Call { .. } => "Call",
+        TerminatorKind::Assert { .. } => "Assert",
+        TerminatorKind::Yield { .. } => "Yield",
+        TerminatorKind::GeneratorDrop => "GeneratorDrop",
+        TerminatorKind::FalseEdge { .. } => "FalseEdge",
+        TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
+        TerminatorKind::InlineAsm { .. } => "InlineAsm",
+    }
+}
+
+/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
+/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s.
+/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent
+/// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the
+/// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s.
+///
+/// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that
+/// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches
+/// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock`
+/// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`.
+#[derive(Debug, Clone)]
+struct CoverageSpan {
+    span: Span,
+    bcb_leader_bb: BasicBlock,
+    coverage_statements: Vec<CoverageStatement>,
+    is_closure: bool,
+}
+
+impl CoverageSpan {
+    pub fn for_statement(
+        statement: &Statement<'tcx>,
+        span: Span,
+        bcb: &BasicCoverageBlock,
+        bb: BasicBlock,
+        stmt_index: usize,
+    ) -> Self {
+        let is_closure = match statement.kind {
+            StatementKind::Assign(box (
+                _,
+                Rvalue::Aggregate(box AggregateKind::Closure(_, _), _),
+            )) => true,
+            _ => false,
+        };
+
+        Self {
+            span,
+            bcb_leader_bb: bcb.leader_bb(),
+            coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
+            is_closure,
+        }
+    }
+
+    pub fn for_terminator(span: Span, bcb: &'a BasicCoverageBlock, bb: BasicBlock) -> Self {
+        Self {
+            span,
+            bcb_leader_bb: bcb.leader_bb(),
+            coverage_statements: vec![CoverageStatement::Terminator(bb, span)],
+            is_closure: false,
+        }
+    }
+
+    pub fn merge_from(&mut self, mut other: CoverageSpan) {
+        debug_assert!(self.is_mergeable(&other));
+        self.span = self.span.to(other.span);
+        if other.is_closure {
+            self.is_closure = true;
+        }
+        self.coverage_statements.append(&mut other.coverage_statements);
+    }
+
+    pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) {
+        self.coverage_statements.retain(|covstmt| covstmt.span().hi() <= cutoff_pos);
+        if let Some(highest_covstmt) =
+            self.coverage_statements.iter().max_by_key(|covstmt| covstmt.span().hi())
+        {
+            self.span = self.span.with_hi(highest_covstmt.span().hi());
+        }
+    }
+
+    pub fn is_dominated_by(
+        &self,
+        other: &CoverageSpan,
+        dominators: &Dominators<BasicBlock>,
+    ) -> bool {
+        debug_assert!(!self.is_in_same_bcb(other));
+        dominators.is_dominated_by(self.bcb_leader_bb, other.bcb_leader_bb)
+    }
+
+    pub fn is_mergeable(&self, other: &Self) -> bool {
+        self.is_in_same_bcb(other) && !(self.is_closure || other.is_closure)
+    }
+
+    pub fn is_in_same_bcb(&self, other: &Self) -> bool {
+        self.bcb_leader_bb == other.bcb_leader_bb
+    }
 }
 
 struct Instrumentor<'a, 'tcx> {
     pass_name: &'a str,
     tcx: TyCtxt<'tcx>,
-    mir_source: MirSource<'tcx>,
     mir_body: &'a mut mir::Body<'tcx>,
     hir_body: &'tcx rustc_hir::Body<'tcx>,
+    dominators: Option<Dominators<BasicBlock>>,
+    basic_coverage_blocks: Option<BasicCoverageBlocks>,
     function_source_hash: Option<u64>,
-    num_counters: u32,
+    next_counter_id: u32,
     num_expressions: u32,
 }
 
 impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
-    fn new(
-        pass_name: &'a str,
-        tcx: TyCtxt<'tcx>,
-        mir_source: MirSource<'tcx>,
-        mir_body: &'a mut mir::Body<'tcx>,
-    ) -> Self {
-        let hir_body = hir_body(tcx, mir_source.def_id());
+    fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
+        let hir_body = hir_body(tcx, mir_body.source.def_id());
         Self {
             pass_name,
             tcx,
-            mir_source,
             mir_body,
             hir_body,
+            dominators: None,
+            basic_coverage_blocks: None,
             function_source_hash: None,
-            num_counters: 0,
+            next_counter_id: CounterValueReference::START.as_u32(),
             num_expressions: 0,
         }
     }
 
-    /// Counter IDs start from zero and go up.
+    /// Counter IDs start from one and go up.
     fn next_counter(&mut self) -> CounterValueReference {
-        assert!(self.num_counters < u32::MAX - self.num_expressions);
-        let next = self.num_counters;
-        self.num_counters += 1;
+        assert!(self.next_counter_id < u32::MAX - self.num_expressions);
+        let next = self.next_counter_id;
+        self.next_counter_id += 1;
         CounterValueReference::from(next)
     }
 
@@ -137,12 +513,22 @@
     /// (add or subtract counts) of both Counter regions and CounterExpression regions. The counter
     /// expression operand IDs must be unique across both types.
     fn next_expression(&mut self) -> InjectedExpressionIndex {
-        assert!(self.num_counters < u32::MAX - self.num_expressions);
+        assert!(self.next_counter_id < u32::MAX - self.num_expressions);
         let next = u32::MAX - self.num_expressions;
         self.num_expressions += 1;
         InjectedExpressionIndex::from(next)
     }
 
+    fn dominators(&self) -> &Dominators<BasicBlock> {
+        self.dominators.as_ref().expect("dominators must be initialized before calling")
+    }
+
+    fn basic_coverage_blocks(&self) -> &BasicCoverageBlocks {
+        self.basic_coverage_blocks
+            .as_ref()
+            .expect("basic_coverage_blocks must be initialized before calling")
+    }
+
     fn function_source_hash(&mut self) -> u64 {
         match self.function_source_hash {
             Some(hash) => hash,
@@ -156,122 +542,73 @@
 
     fn inject_counters(&mut self) {
         let tcx = self.tcx;
-        let def_id = self.mir_source.def_id();
+        let source_map = tcx.sess.source_map();
+        let def_id = self.mir_body.source.def_id();
         let mir_body = &self.mir_body;
-        let body_span = self.hir_body.value.span;
-        debug!(
-            "instrumenting {:?}, span: {}",
-            def_id,
-            tcx.sess.source_map().span_to_string(body_span)
-        );
+        let body_span = self.body_span();
+        let source_file = source_map.lookup_source_file(body_span.lo());
+        let file_name = Symbol::intern(&source_file.name.to_string());
 
-        if !tcx.sess.opts.debugging_opts.experimental_coverage {
-            // Coverage at the function level should be accurate. This is the default implementation
-            // if `-Z experimental-coverage` is *NOT* enabled.
-            let block = rustc_middle::mir::START_BLOCK;
-            let counter = self.make_counter();
-            self.inject_statement(counter, body_span, block);
-            return;
-        }
-        // FIXME(richkadel): else if `-Z experimental-coverage` *IS* enabled: Efforts are still in
-        // progress to identify the correct code region spans and associated counters to generate
-        // accurate Rust coverage reports.
+        debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span));
 
-        let block_span = |data: &BasicBlockData<'tcx>| {
-            // The default span will be the `Terminator` span; but until we have a smarter solution,
-            // the coverage region also incorporates at least the statements in this BasicBlock as
-            // well. Extend the span to encompass all, if possible.
-            // FIXME(richkadel): Assuming the terminator's span is already known to be contained in `body_span`.
-            let mut span = data.terminator().source_info.span;
-            // FIXME(richkadel): It's looking unlikely that we should compute a span from MIR
-            // spans, but if we do keep something like this logic, we will need a smarter way
-            // to combine `Statement`s and/or `Terminator`s with `Span`s from different
-            // files.
-            for statement_span in data.statements.iter().map(|statement| statement.source_info.span)
-            {
-                // Only combine Spans from the function's body_span.
-                if body_span.contains(statement_span) {
-                    span = span.to(statement_span);
-                }
-            }
-            span
-        };
+        self.dominators.replace(mir_body.dominators());
+        self.basic_coverage_blocks.replace(BasicCoverageBlocks::from_mir(mir_body));
 
-        // Traverse the CFG but ignore anything following an `unwind`
-        let cfg_without_unwind = ShortCircuitPreorder::new(mir_body, |term_kind| {
-            let mut successors = term_kind.successors();
-            match &term_kind {
-                // SwitchInt successors are never unwind, and all of them should be traversed
-                TerminatorKind::SwitchInt { .. } => successors,
-                // For all other kinds, return only the first successor, if any, and ignore unwinds
-                _ => successors.next().into_iter().chain(&[]),
-            }
-        });
-
-        let mut coverage_regions = Vec::with_capacity(cfg_without_unwind.size_hint().0);
-        for (bb, data) in cfg_without_unwind {
-            if !body_span.contains(data.terminator().source_info.span) {
-                continue;
-            }
-
-            // FIXME(richkadel): Regions will soon contain multiple blocks.
-            let mut blocks = Vec::new();
-            blocks.push(bb);
-            let span = block_span(data);
-            coverage_regions.push(CoverageRegion { span, blocks });
-        }
+        let coverage_spans = self.coverage_spans();
 
         let span_viewables = if pretty::dump_enabled(tcx, self.pass_name, def_id) {
-            Some(self.span_viewables(&coverage_regions))
+            Some(self.span_viewables(&coverage_spans))
         } else {
             None
         };
 
-        // Inject counters for the selected spans
-        for CoverageRegion { span, blocks } in coverage_regions {
-            debug!(
-                "Injecting counter at: {:?}:\n{}\n==========",
-                span,
-                tcx.sess.source_map().span_to_snippet(span).expect("Error getting source for span"),
-            );
-            let counter = self.make_counter();
-            self.inject_statement(counter, span, blocks[0]);
+        // Inject a counter for each `CoverageSpan`. There can be multiple `CoverageSpan`s for a
+        // given BCB, but only one actual counter needs to be incremented per BCB. `bb_counters`
+        // maps each `bcb_leader_bb` to its `Counter`, when injected. Subsequent `CoverageSpan`s
+        // for a BCB that already has a `Counter` will inject a `CounterExpression` instead, and
+        // compute its value by adding `ZERO` to the BCB `Counter` value.
+        let mut bb_counters = IndexVec::from_elem_n(None, mir_body.basic_blocks().len());
+        for CoverageSpan { span, bcb_leader_bb: bb, .. } in coverage_spans {
+            if let Some(&counter_operand) = bb_counters[bb].as_ref() {
+                let expression =
+                    self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO);
+                debug!(
+                    "Injecting counter expression {:?} at: {:?}:\n{}\n==========",
+                    expression,
+                    span,
+                    source_map.span_to_snippet(span).expect("Error getting source for span"),
+                );
+                self.inject_statement(file_name, &source_file, expression, span, bb);
+            } else {
+                let counter = self.make_counter();
+                debug!(
+                    "Injecting counter {:?} at: {:?}:\n{}\n==========",
+                    counter,
+                    span,
+                    source_map.span_to_snippet(span).expect("Error getting source for span"),
+                );
+                let counter_operand = counter.as_operand_id();
+                bb_counters[bb] = Some(counter_operand);
+                self.inject_statement(file_name, &source_file, counter, span, bb);
+            }
         }
 
         if let Some(span_viewables) = span_viewables {
-            let mut file =
-                pretty::create_dump_file(tcx, "html", None, self.pass_name, &0, self.mir_source)
-                    .expect("Unexpected error creating MIR spanview HTML file");
-            write_spanview_document(tcx, def_id, span_viewables, &mut file)
+            let mut file = pretty::create_dump_file(
+                tcx,
+                "html",
+                None,
+                self.pass_name,
+                &0,
+                self.mir_body.source,
+            )
+            .expect("Unexpected error creating MIR spanview HTML file");
+            let crate_name = tcx.crate_name(def_id.krate);
+            let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
+            let title = format!("{}.{} - Coverage Spans", crate_name, item_name);
+            spanview::write_document(tcx, def_id, span_viewables, &title, &mut file)
                 .expect("Unexpected IO error dumping coverage spans as HTML");
         }
-
-        // FIXME(richkadel): Some regions will be counted by "counter expression". Counter
-        // expressions are supported, but are not yet generated. When they are, remove this `fake_use`
-        // block.
-        let fake_use = false;
-        if fake_use {
-            let add = false;
-            let fake_counter = CoverageKind::Counter {
-                function_source_hash: self.function_source_hash(),
-                id: CounterValueReference::from_u32(1),
-            };
-            let fake_expression = CoverageKind::Expression {
-                id: InjectedExpressionIndex::from(u32::MAX - 1),
-                lhs: ExpressionOperandId::from_u32(1),
-                op: Op::Add,
-                rhs: ExpressionOperandId::from_u32(2),
-            };
-
-            let lhs = fake_counter.as_operand_id();
-            let op = if add { Op::Add } else { Op::Subtract };
-            let rhs = fake_expression.as_operand_id();
-
-            let block = rustc_middle::mir::START_BLOCK;
-
-            let expression = self.make_expression(lhs, op, rhs);
-            self.inject_statement(expression, body_span, block);
-        }
     }
 
     fn make_counter(&mut self) -> CoverageKind {
@@ -290,8 +627,15 @@
         CoverageKind::Expression { id: self.next_expression(), lhs, op, rhs }
     }
 
-    fn inject_statement(&mut self, coverage_kind: CoverageKind, span: Span, block: BasicBlock) {
-        let code_region = make_code_region(self.tcx, &span);
+    fn inject_statement(
+        &mut self,
+        file_name: Symbol,
+        source_file: &Lrc<SourceFile>,
+        coverage_kind: CoverageKind,
+        span: Span,
+        block: BasicBlock,
+    ) {
+        let code_region = make_code_region(file_name, source_file, span);
         debug!("  injecting statement {:?} covering {:?}", coverage_kind, code_region);
 
         let data = &mut self.mir_body[block];
@@ -303,112 +647,548 @@
         data.statements.push(statement);
     }
 
-    /// Converts the computed `CoverageRegion`s into `SpanViewable`s.
-    fn span_viewables(&self, coverage_regions: &Vec<CoverageRegion>) -> Vec<SpanViewable> {
+    /// Converts the computed `BasicCoverageBlock`s into `SpanViewable`s.
+    fn span_viewables(&self, coverage_spans: &Vec<CoverageSpan>) -> Vec<SpanViewable> {
+        let tcx = self.tcx;
+        let mir_body = &self.mir_body;
         let mut span_viewables = Vec::new();
-        for coverage_region in coverage_regions {
-            span_viewables.push(SpanViewable {
-                span: coverage_region.span,
-                id: format!("{}", coverage_region.blocks[0].index()),
-                tooltip: self.make_tooltip_text(coverage_region),
+        for coverage_span in coverage_spans {
+            let bcb = self.bcb_from_coverage_span(coverage_span);
+            let CoverageSpan { span, bcb_leader_bb: bb, coverage_statements, .. } = coverage_span;
+            let id = bcb.id();
+            let mut sorted_coverage_statements = coverage_statements.clone();
+            sorted_coverage_statements.sort_unstable_by_key(|covstmt| match *covstmt {
+                CoverageStatement::Statement(bb, _, index) => (bb, index),
+                CoverageStatement::Terminator(bb, _) => (bb, usize::MAX),
             });
+            let tooltip = sorted_coverage_statements
+                .iter()
+                .map(|covstmt| covstmt.format(tcx, mir_body))
+                .collect::<Vec<_>>()
+                .join("\n");
+            span_viewables.push(SpanViewable { bb: *bb, span: *span, id, tooltip });
         }
         span_viewables
     }
 
-    /// A custom tooltip renderer used in a spanview HTML+CSS document used for coverage analysis.
-    fn make_tooltip_text(&self, coverage_region: &CoverageRegion) -> String {
-        const INCLUDE_COVERAGE_STATEMENTS: bool = false;
-        let tcx = self.tcx;
-        let source_map = tcx.sess.source_map();
-        let mut text = Vec::new();
-        for (i, &bb) in coverage_region.blocks.iter().enumerate() {
-            if i > 0 {
-                text.push("\n".to_owned());
+    #[inline(always)]
+    fn bcb_from_coverage_span(&self, coverage_span: &CoverageSpan) -> &BasicCoverageBlock {
+        &self.basic_coverage_blocks()[coverage_span.bcb_leader_bb]
+    }
+
+    #[inline(always)]
+    fn body_span(&self) -> Span {
+        self.hir_body.value.span
+    }
+
+    // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
+    // the `BasicBlock`(s) in the given `BasicCoverageBlock`. One `CoverageSpan` is generated for
+    // each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
+    // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
+    // `Statement`s and/or `Terminator`s.)
+    fn extract_spans(&self, bcb: &'a BasicCoverageBlock) -> Vec<CoverageSpan> {
+        let body_span = self.body_span();
+        let mir_basic_blocks = self.mir_body.basic_blocks();
+        bcb.blocks
+            .iter()
+            .map(|bbref| {
+                let bb = *bbref;
+                let data = &mir_basic_blocks[bb];
+                data.statements
+                    .iter()
+                    .enumerate()
+                    .filter_map(move |(index, statement)| {
+                        filtered_statement_span(statement, body_span).map(|span| {
+                            CoverageSpan::for_statement(statement, span, bcb, bb, index)
+                        })
+                    })
+                    .chain(
+                        filtered_terminator_span(data.terminator(), body_span)
+                            .map(|span| CoverageSpan::for_terminator(span, bcb, bb)),
+                    )
+            })
+            .flatten()
+            .collect()
+    }
+
+    /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
+    /// counted.
+    ///
+    /// The basic steps are:
+    ///
+    /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
+    ///    `BasicCoverageBlock`.
+    /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
+    ///    are sorted with longer spans before shorter spans; and equal spans are sorted
+    ///    (deterministically) based on "dominator" relationship (if any).
+    /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
+    ///    if another span or spans are already counting the same code region), or should be merged
+    ///    into a broader combined span (because it represents a contiguous, non-branching, and
+    ///    uninterrupted region of source code).
+    ///
+    ///    Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
+    ///    closures have their own MIR, their `Span` in their enclosing function should be left
+    ///    "uncovered".
+    ///
+    /// Note the resulting vector of `CoverageSpan`s does may not be fully sorted (and does not need
+    /// to be).
+    fn coverage_spans(&self) -> Vec<CoverageSpan> {
+        let mut initial_spans =
+            Vec::<CoverageSpan>::with_capacity(self.mir_body.basic_blocks().len() * 2);
+        for bcb in self.basic_coverage_blocks().iter() {
+            for coverage_span in self.extract_spans(bcb) {
+                initial_spans.push(coverage_span);
             }
-            text.push(format!("{:?}: {}:", bb, &source_map.span_to_string(coverage_region.span)));
-            let data = &self.mir_body.basic_blocks()[bb];
-            for statement in &data.statements {
-                let statement_string = match statement.kind {
-                    StatementKind::Coverage(box ref coverage) => match coverage.kind {
-                        CoverageKind::Counter { id, .. } => {
-                            if !INCLUDE_COVERAGE_STATEMENTS {
-                                continue;
-                            }
-                            format!("increment counter #{}", id.index())
-                        }
-                        CoverageKind::Expression { id, lhs, op, rhs } => {
-                            if !INCLUDE_COVERAGE_STATEMENTS {
-                                continue;
-                            }
-                            format!(
-                                "expression #{} = {} {} {}",
-                                id.index(),
-                                lhs.index(),
-                                if op == Op::Add { "+" } else { "-" },
-                                rhs.index()
-                            )
-                        }
-                        CoverageKind::Unreachable => {
-                            if !INCLUDE_COVERAGE_STATEMENTS {
-                                continue;
-                            }
-                            String::from("unreachable")
-                        }
-                    },
-                    _ => format!("{:?}", statement),
-                };
-                let source_range = source_range_no_file(tcx, &statement.source_info.span);
-                text.push(format!(
-                    "\n{}{}: {}: {}",
-                    TOOLTIP_INDENT,
-                    source_range,
-                    statement_kind_name(statement),
-                    statement_string
-                ));
-            }
-            let term = data.terminator();
-            let source_range = source_range_no_file(tcx, &term.source_info.span);
-            text.push(format!(
-                "\n{}{}: {}: {:?}",
-                TOOLTIP_INDENT,
-                source_range,
-                terminator_kind_name(term),
-                term.kind
-            ));
         }
-        text.join("")
+
+        if initial_spans.is_empty() {
+            // This can happen if, for example, the function is unreachable (contains only a
+            // `BasicBlock`(s) with an `Unreachable` terminator).
+            return initial_spans;
+        }
+
+        initial_spans.sort_unstable_by(|a, b| {
+            if a.span.lo() == b.span.lo() {
+                if a.span.hi() == b.span.hi() {
+                    if a.is_in_same_bcb(b) {
+                        Some(Ordering::Equal)
+                    } else {
+                        // Sort equal spans by dominator relationship, in reverse order (so
+                        // dominators always come after the dominated equal spans). When later
+                        // comparing two spans in order, the first will either dominate the second,
+                        // or they will have no dominator relationship.
+                        self.dominators().rank_partial_cmp(b.bcb_leader_bb, a.bcb_leader_bb)
+                    }
+                } else {
+                    // Sort hi() in reverse order so shorter spans are attempted after longer spans.
+                    // This guarantees that, if a `prev` span overlaps, and is not equal to, a `curr`
+                    // span, the prev span either extends further left of the curr span, or they
+                    // start at the same position and the prev span extends further right of the end
+                    // of the curr span.
+                    b.span.hi().partial_cmp(&a.span.hi())
+                }
+            } else {
+                a.span.lo().partial_cmp(&b.span.lo())
+            }
+            .unwrap()
+        });
+
+        let refinery = CoverageSpanRefinery::from_sorted_spans(initial_spans, self.dominators());
+        refinery.to_refined_spans()
     }
 }
 
-/// Convert the Span into its file name, start line and column, and end line and column
-fn make_code_region<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> CodeRegion {
-    let source_map = tcx.sess.source_map();
-    let start = source_map.lookup_char_pos(span.lo());
-    let end = if span.hi() == span.lo() {
-        start.clone()
-    } else {
-        let end = source_map.lookup_char_pos(span.hi());
-        debug_assert_eq!(
-            start.file.name,
-            end.file.name,
-            "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!",
-            span.lo(),
-            start,
-            span.hi(),
-            end
+struct CoverageSpanRefinery<'a> {
+    sorted_spans_iter: std::vec::IntoIter<CoverageSpan>,
+    dominators: &'a Dominators<BasicBlock>,
+    some_curr: Option<CoverageSpan>,
+    curr_original_span: Span,
+    some_prev: Option<CoverageSpan>,
+    prev_original_span: Span,
+    pending_dups: Vec<CoverageSpan>,
+    refined_spans: Vec<CoverageSpan>,
+}
+
+impl<'a> CoverageSpanRefinery<'a> {
+    fn from_sorted_spans(
+        sorted_spans: Vec<CoverageSpan>,
+        dominators: &'a Dominators<BasicBlock>,
+    ) -> Self {
+        let refined_spans = Vec::with_capacity(sorted_spans.len());
+        let mut sorted_spans_iter = sorted_spans.into_iter();
+        let prev = sorted_spans_iter.next().expect("at least one span");
+        let prev_original_span = prev.span;
+        Self {
+            sorted_spans_iter,
+            dominators,
+            refined_spans,
+            some_curr: None,
+            curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
+            some_prev: Some(prev),
+            prev_original_span,
+            pending_dups: Vec::new(),
+        }
+    }
+
+    /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
+    /// de-duplicated `CoverageSpan`s.
+    fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
+        while self.next_coverage_span() {
+            if self.curr().is_mergeable(self.prev()) {
+                debug!("  same bcb (and neither is a closure), merge with prev={:?}", self.prev());
+                let prev = self.take_prev();
+                self.curr_mut().merge_from(prev);
+            // Note that curr.span may now differ from curr_original_span
+            } else if self.prev_ends_before_curr() {
+                debug!(
+                    "  different bcbs and disjoint spans, so keep curr for next iter, and add \
+                    prev={:?}",
+                    self.prev()
+                );
+                let prev = self.take_prev();
+                self.add_refined_span(prev);
+            } else if self.prev().is_closure {
+                // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
+                // next iter
+                debug!(
+                    "  curr overlaps a closure (prev). Drop curr and keep prev for next iter. \
+                    prev={:?}",
+                    self.prev()
+                );
+                self.discard_curr();
+            } else if self.curr().is_closure {
+                self.carve_out_span_for_closure();
+            } else if self.prev_original_span == self.curr().span {
+                self.hold_pending_dups_unless_dominated();
+            } else {
+                self.cutoff_prev_at_overlapping_curr();
+            }
+        }
+        debug!("    AT END, adding last prev={:?}", self.prev());
+        let pending_dups = self.pending_dups.split_off(0);
+        for dup in pending_dups.into_iter() {
+            debug!("    ...adding at least one pending dup={:?}", dup);
+            self.add_refined_span(dup);
+        }
+        let prev = self.take_prev();
+        self.add_refined_span(prev);
+
+        // FIXME(richkadel): Replace some counters with expressions if they can be calculated based
+        // on branching. (For example, one branch of a SwitchInt can be computed from the counter
+        // for the CoverageSpan just prior to the SwitchInt minus the sum of the counters of all
+        // other branches).
+
+        self.to_refined_spans_without_closures()
+    }
+
+    fn add_refined_span(&mut self, coverage_span: CoverageSpan) {
+        self.refined_spans.push(coverage_span);
+    }
+
+    /// Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
+    /// regions for the current function leave room for the closure's own coverage regions
+    /// (injected separately, from the closure's own MIR).
+    fn to_refined_spans_without_closures(mut self) -> Vec<CoverageSpan> {
+        self.refined_spans.retain(|covspan| !covspan.is_closure);
+        self.refined_spans
+    }
+
+    fn curr(&self) -> &CoverageSpan {
+        self.some_curr
+            .as_ref()
+            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
+    }
+
+    fn curr_mut(&mut self) -> &mut CoverageSpan {
+        self.some_curr
+            .as_mut()
+            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
+    }
+
+    fn prev(&self) -> &CoverageSpan {
+        self.some_prev
+            .as_ref()
+            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
+    }
+
+    fn prev_mut(&mut self) -> &mut CoverageSpan {
+        self.some_prev
+            .as_mut()
+            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
+    }
+
+    fn take_prev(&mut self) -> CoverageSpan {
+        self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
+    }
+
+    /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the
+    /// `pending_dups` spans), then one of the following two things happened during the previous
+    /// iteration:
+    ///   * the `span` of prev was modified (by `curr_mut().merge_from(prev)`); or
+    ///   * the `span` of prev advanced past the end of the span of pending_dups
+    ///     (`prev().span.hi() <= curr().span.lo()`)
+    /// In either case, no more spans will match the span of `pending_dups`, so
+    /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
+    fn check_pending_dups(&mut self) {
+        if let Some(dup) = self.pending_dups.last() {
+            if dup.span != self.prev().span {
+                debug!(
+                    "    SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
+                    previous iteration, or prev started a new disjoint span"
+                );
+                if dup.span.hi() <= self.curr().span.lo() {
+                    let pending_dups = self.pending_dups.split_off(0);
+                    for dup in pending_dups.into_iter() {
+                        debug!("    ...adding at least one pending={:?}", dup);
+                        self.add_refined_span(dup);
+                    }
+                } else {
+                    self.pending_dups.clear();
+                }
+            }
+        }
+    }
+
+    /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
+    fn next_coverage_span(&mut self) -> bool {
+        if let Some(curr) = self.some_curr.take() {
+            self.some_prev = Some(curr);
+            self.prev_original_span = self.curr_original_span;
+        }
+        while let Some(curr) = self.sorted_spans_iter.next() {
+            debug!("FOR curr={:?}", curr);
+            if self.prev_starts_after_next(&curr) {
+                debug!(
+                    "  prev.span starts after curr.span, so curr will be dropped (skipping past \
+                    closure?); prev={:?}",
+                    self.prev()
+                );
+            } else {
+                // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed
+                // by `self.curr_mut().merge_from(prev)`.
+                self.curr_original_span = curr.span;
+                self.some_curr.replace(curr);
+                self.check_pending_dups();
+                return true;
+            }
+        }
+        false
+    }
+
+    /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
+    /// `curr` coverage span.
+    fn discard_curr(&mut self) {
+        self.some_curr = None;
+    }
+
+    /// Returns true if the curr span should be skipped because prev has already advanced beyond the
+    /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region
+    /// of code, such as skipping past a closure.
+    fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool {
+        self.prev().span.lo() > next_curr.span.lo()
+    }
+
+    /// Returns true if the curr span starts past the end of the prev span, which means they don't
+    /// overlap, so we now know the prev can be added to the refined coverage spans.
+    fn prev_ends_before_curr(&self) -> bool {
+        self.prev().span.hi() <= self.curr().span.lo()
+    }
+
+    /// If `prev`s span extends left of the closure (`curr`), carve out the closure's
+    /// span from `prev`'s span. (The closure's coverage counters will be injected when
+    /// processing the closure's own MIR.) Add the portion of the span to the left of the
+    /// closure; and if the span extends to the right of the closure, update `prev` to
+    /// that portion of the span. For any `pending_dups`, repeat the same process.
+    fn carve_out_span_for_closure(&mut self) {
+        let curr_span = self.curr().span;
+        let left_cutoff = curr_span.lo();
+        let right_cutoff = curr_span.hi();
+        let has_pre_closure_span = self.prev().span.lo() < right_cutoff;
+        let has_post_closure_span = self.prev().span.hi() > right_cutoff;
+        let mut pending_dups = self.pending_dups.split_off(0);
+        if has_pre_closure_span {
+            let mut pre_closure = self.prev().clone();
+            pre_closure.span = pre_closure.span.with_hi(left_cutoff);
+            debug!("  prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure);
+            if !pending_dups.is_empty() {
+                for mut dup in pending_dups.iter().cloned() {
+                    dup.span = dup.span.with_hi(left_cutoff);
+                    debug!("    ...and at least one pre_closure dup={:?}", dup);
+                    self.add_refined_span(dup);
+                }
+            }
+            self.add_refined_span(pre_closure);
+        }
+        if has_post_closure_span {
+            // Update prev.span to start after the closure (and discard curr)
+            self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
+            self.prev_original_span = self.prev().span;
+            for dup in pending_dups.iter_mut() {
+                dup.span = dup.span.with_lo(right_cutoff);
+            }
+            self.pending_dups.append(&mut pending_dups);
+            self.discard_curr(); // since self.prev() was already updated
+        } else {
+            pending_dups.clear();
+        }
+    }
+
+    /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
+    /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
+    /// until their disposition is determined. In this latter case, the `prev` dup is moved into
+    /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
+    fn hold_pending_dups_unless_dominated(&mut self) {
+        // equal coverage spans are ordered by dominators before dominated (if any)
+        debug_assert!(!self.prev().is_dominated_by(self.curr(), self.dominators));
+
+        if self.curr().is_dominated_by(&self.prev(), self.dominators) {
+            // If one span dominates the other, assocate the span with the dominator only.
+            //
+            // For example:
+            //     match somenum {
+            //         x if x < 1 => { ... }
+            //     }...
+            // The span for the first `x` is referenced by both the pattern block (every
+            // time it is evaluated) and the arm code (only when matched). The counter
+            // will be applied only to the dominator block.
+            //
+            // The dominator's (`prev`) execution count may be higher than the dominated
+            // block's execution count, so drop `curr`.
+            debug!(
+                "  different bcbs but SAME spans, and prev dominates curr. Drop curr and \
+                keep prev for next iter. prev={:?}",
+                self.prev()
+            );
+            self.discard_curr();
+        } else {
+            // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.)
+            // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as
+            // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added.
+            debug!(
+                "  different bcbs but SAME spans, and neither dominates, so keep curr for \
+                next iter, and, pending upcoming spans (unless overlapping) add prev={:?}",
+                self.prev()
+            );
+            let prev = self.take_prev();
+            self.pending_dups.push(prev);
+        }
+    }
+
+    /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
+    /// statements that end before `curr.lo()` (if any), and add the portion of the
+    /// combined span for those statements. Any other statements have overlapping spans
+    /// that can be ignored because `curr` and/or other upcoming statements/spans inside
+    /// the overlap area will produce their own counters. This disambiguation process
+    /// avoids injecting multiple counters for overlapping spans, and the potential for
+    /// double-counting.
+    fn cutoff_prev_at_overlapping_curr(&mut self) {
+        debug!(
+            "  different bcbs, overlapping spans, so ignore/drop pending and only add prev \
+            if it has statements that end before curr={:?}",
+            self.prev()
         );
-        end
+        if self.pending_dups.is_empty() {
+            let curr_span = self.curr().span;
+            self.prev_mut().cutoff_statements_at(curr_span.lo());
+            if self.prev().coverage_statements.is_empty() {
+                debug!("  ... no non-overlapping statements to add");
+            } else {
+                debug!("  ... adding modified prev={:?}", self.prev());
+                let prev = self.take_prev();
+                self.add_refined_span(prev);
+            }
+        } else {
+            // with `pending_dups`, `prev` cannot have any statements that don't overlap
+            self.pending_dups.clear();
+        }
+    }
+}
+
+fn filtered_statement_span(statement: &'a Statement<'tcx>, body_span: Span) -> Option<Span> {
+    match statement.kind {
+        // These statements have spans that are often outside the scope of the executed source code
+        // for their parent `BasicBlock`.
+        StatementKind::StorageLive(_)
+        | StatementKind::StorageDead(_)
+        // Coverage should not be encountered, but don't inject coverage coverage
+        | StatementKind::Coverage(_)
+        // Ignore `Nop`s
+        | StatementKind::Nop => None,
+
+        // FIXME(richkadel): Look into a possible issue assigning the span to a
+        // FakeReadCause::ForGuardBinding, in this example:
+        //     match somenum {
+        //         x if x < 1 => { ... }
+        //     }...
+        // The BasicBlock within the match arm code included one of these statements, but the span
+        // for it covered the `1` in this source. The actual statements have nothing to do with that
+        // source span:
+        //     FakeRead(ForGuardBinding, _4);
+        // where `_4` is:
+        //     _4 = &_1; (at the span for the first `x`)
+        // and `_1` is the `Place` for `somenum`.
+        //
+        // The arm code BasicBlock already has its own assignment for `x` itself, `_3 = 1`, and I've
+        // decided it's reasonable for that span (even though outside the arm code) to be part of
+        // the counted coverage of the arm code execution, but I can't justify including the literal
+        // `1` in the arm code. I'm pretty sure that, if the `FakeRead(ForGuardBinding)` has a
+        // purpose in codegen, it's probably in the right BasicBlock, but if so, the `Statement`s
+        // `source_info.span` can't be right.
+        //
+        // Consider correcting the span assignment, assuming there is a better solution, and see if
+        // the following pattern can be removed here:
+        StatementKind::FakeRead(cause, _) if cause == FakeReadCause::ForGuardBinding => None,
+
+        // Retain spans from all other statements
+        StatementKind::FakeRead(_, _) // Not including `ForGuardBinding`
+        | StatementKind::Assign(_)
+        | StatementKind::SetDiscriminant { .. }
+        | StatementKind::LlvmInlineAsm(_)
+        | StatementKind::Retag(_, _)
+        | StatementKind::AscribeUserType(_, _) => {
+            Some(source_info_span(&statement.source_info, body_span))
+        }
+    }
+}
+
+fn filtered_terminator_span(terminator: &'a Terminator<'tcx>, body_span: Span) -> Option<Span> {
+    match terminator.kind {
+        // These terminators have spans that don't positively contribute to computing a reasonable
+        // span of actually executed source code. (For example, SwitchInt terminators extracted from
+        // an `if condition { block }` has a span that includes the executed block, if true,
+        // but for coverage, the code region executed, up to *and* through the SwitchInt,
+        // actually stops before the if's block.)
+        TerminatorKind::Unreachable // Unreachable blocks are not connected to the CFG
+        | TerminatorKind::Assert { .. }
+        | TerminatorKind::Drop { .. }
+        | TerminatorKind::DropAndReplace { .. }
+        | TerminatorKind::SwitchInt { .. }
+        | TerminatorKind::Goto { .. }
+        // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
+        | TerminatorKind::FalseEdge { .. } => None,
+
+        // Retain spans from all other terminators
+        TerminatorKind::Resume
+        | TerminatorKind::Abort
+        | TerminatorKind::Return
+        | TerminatorKind::Call { .. }
+        | TerminatorKind::Yield { .. }
+        | TerminatorKind::GeneratorDrop
+        | TerminatorKind::FalseUnwind { .. }
+        | TerminatorKind::InlineAsm { .. } => {
+            Some(source_info_span(&terminator.source_info, body_span))
+        }
+    }
+}
+
+#[inline(always)]
+fn source_info_span(source_info: &SourceInfo, body_span: Span) -> Span {
+    let span = original_sp(source_info.span, body_span).with_ctxt(SyntaxContext::root());
+    if body_span.contains(span) { span } else { body_span }
+}
+
+/// Convert the Span into its file name, start line and column, and end line and column
+fn make_code_region(file_name: Symbol, source_file: &Lrc<SourceFile>, span: Span) -> CodeRegion {
+    let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo());
+    let (end_line, end_col) = if span.hi() == span.lo() {
+        let (end_line, mut end_col) = (start_line, start_col);
+        // Extend an empty span by one character so the region will be counted.
+        let CharPos(char_pos) = start_col;
+        if char_pos > 0 {
+            start_col = CharPos(char_pos - 1);
+        } else {
+            end_col = CharPos(char_pos + 1);
+        }
+        (end_line, end_col)
+    } else {
+        source_file.lookup_file_pos(span.hi())
     };
-    match &start.file.name {
-        FileName::Real(RealFileName::Named(path)) => CodeRegion {
-            file_name: Symbol::intern(&path.to_string_lossy()),
-            start_line: start.line as u32,
-            start_col: start.col.to_u32() + 1,
-            end_line: end.line as u32,
-            end_col: end.col.to_u32() + 1,
-        },
-        _ => bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name),
+    CodeRegion {
+        file_name,
+        start_line: start_line as u32,
+        start_col: start_col.to_u32() + 1,
+        end_line: end_line as u32,
+        end_col: end_col.to_u32() + 1,
     }
 }
 
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index c1d574d..0f9b2ff 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -1,4 +1,4 @@
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
@@ -37,8 +37,15 @@
 /// ```
 
 impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(src.def_id());
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        // FIXME: This optimization can result in unsoundness, because it introduces
+        // additional uses of a place holding the discriminant value without ensuring that
+        // it is valid to do so.
+        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
+            return;
+        }
+
+        let param_env = tcx.param_env(body.source.def_id());
         let bbs = body.basic_blocks_mut();
         'outer: for bb_idx in bbs.indices() {
             let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
@@ -46,10 +53,13 @@
                     discr: Operand::Copy(ref place) | Operand::Move(ref place),
                     switch_ty,
                     ref targets,
-                    ref values,
                     ..
-                } if targets.len() == 2 && values.len() == 1 && targets[0] != targets[1] => {
-                    (place, values[0], switch_ty, targets[0], targets[1])
+                } if targets.iter().len() == 1 => {
+                    let (value, target) = targets.iter().next().unwrap();
+                    if target == targets.otherwise() {
+                        continue;
+                    }
+                    (place, value, switch_ty, target, targets.otherwise())
                 }
                 // Only optimize switch int statements
                 _ => continue,
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index 850cafc..20b8c90 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -9,7 +9,7 @@
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::steal::Steal;
-use rustc_middle::ty::{self, InstanceDef, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
@@ -22,7 +22,6 @@
 pub mod check_unsafety;
 pub mod cleanup_post_borrowck;
 pub mod const_prop;
-pub mod copy_prop;
 pub mod deaggregator;
 pub mod dest_prop;
 pub mod dump_mir;
@@ -33,6 +32,7 @@
 pub mod instcombine;
 pub mod instrument_coverage;
 pub mod match_branches;
+pub mod multiple_return_terminators;
 pub mod no_landing_pads;
 pub mod nrvo;
 pub mod promote_consts;
@@ -48,6 +48,8 @@
 pub mod unreachable_prop;
 pub mod validate;
 
+pub use rustc_middle::mir::MirSource;
+
 pub(crate) fn provide(providers: &mut Providers) {
     self::check_unsafety::provide(providers);
     *providers = Providers {
@@ -131,37 +133,10 @@
     set
 }
 
-/// Where a specific `mir::Body` comes from.
-#[derive(Debug, Copy, Clone)]
-pub struct MirSource<'tcx> {
-    pub instance: InstanceDef<'tcx>,
-
-    /// If `Some`, this is a promoted rvalue within the parent function.
-    pub promoted: Option<Promoted>,
-}
-
-impl<'tcx> MirSource<'tcx> {
-    pub fn item(def_id: DefId) -> Self {
-        MirSource {
-            instance: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
-            promoted: None,
-        }
-    }
-
-    pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
-        self.instance.with_opt_param()
-    }
-
-    #[inline]
-    pub fn def_id(&self) -> DefId {
-        self.instance.def_id()
-    }
-}
-
 /// Generates a default name for the pass based on the name of the
 /// type `T`.
 pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
-    let name = ::std::any::type_name::<T>();
+    let name = std::any::type_name::<T>();
     if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) }
 }
 
@@ -173,19 +148,16 @@
         default_name::<Self>()
     }
 
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>);
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
 }
 
 pub fn run_passes(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
-    instance: InstanceDef<'tcx>,
-    promoted: Option<Promoted>,
     mir_phase: MirPhase,
     passes: &[&[&dyn MirPass<'tcx>]],
 ) {
     let phase_index = mir_phase.phase_index();
-    let source = MirSource { instance, promoted };
     let validate = tcx.sess.opts.debugging_opts.validate_mir;
 
     if body.phase >= mir_phase {
@@ -194,7 +166,7 @@
 
     if validate {
         validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase }
-            .run_pass(tcx, source, body);
+            .run_pass(tcx, body);
     }
 
     let mut index = 0;
@@ -204,13 +176,12 @@
                 tcx,
                 &format_args!("{:03}-{:03}", phase_index, index),
                 &pass.name(),
-                source,
                 body,
                 is_after,
             );
         };
         run_hooks(body, index, false);
-        pass.run_pass(tcx, source, body);
+        pass.run_pass(tcx, body);
         run_hooks(body, index, true);
 
         if validate {
@@ -218,7 +189,7 @@
                 when: format!("after {} in phase {:?}", pass.name(), mir_phase),
                 mir_phase,
             }
-            .run_pass(tcx, source, body);
+            .run_pass(tcx, body);
         }
 
         index += 1;
@@ -234,7 +205,7 @@
 
     if mir_phase == MirPhase::Optimization {
         validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase }
-            .run_pass(tcx, source, body);
+            .run_pass(tcx, body);
     }
 }
 
@@ -257,13 +228,7 @@
         return Default::default();
     }
 
-    let ccx = check_consts::ConstCx {
-        body,
-        tcx,
-        def_id: def.did,
-        const_kind,
-        param_env: tcx.param_env(def.did),
-    };
+    let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) };
 
     let mut validator = check_consts::validation::Validator::new(&ccx);
     validator.check_body();
@@ -291,21 +256,11 @@
 
     let mut body = tcx.mir_built(def).steal();
 
-    util::dump_mir(
-        tcx,
-        None,
-        "mir_map",
-        &0,
-        MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None },
-        &body,
-        |_, _| Ok(()),
-    );
+    util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
 
     run_passes(
         tcx,
         &mut body,
-        InstanceDef::Item(def.to_global()),
-        None,
         MirPhase::Const,
         &[&[
             // MIR-level lints.
@@ -331,11 +286,7 @@
     // this point, before we steal the mir-const result.
     // Also this means promotion can rely on all const checks having been done.
     let _ = tcx.mir_const_qualif_opt_const_arg(def);
-    let _ = if let Some(param_did) = def.const_param_did {
-        tcx.mir_abstract_const_of_const_arg((def.did, param_did))
-    } else {
-        tcx.mir_abstract_const(def.did.to_def_id())
-    };
+    let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global());
     let mut body = tcx.mir_const(def).steal();
 
     let mut required_consts = Vec::new();
@@ -358,14 +309,7 @@
         &[]
     };
 
-    run_passes(
-        tcx,
-        &mut body,
-        InstanceDef::Item(def.to_global()),
-        None,
-        MirPhase::ConstPromotion,
-        &[promote, opt_coverage],
-    );
+    run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]);
 
     let promoted = promote_pass.promoted_fragments.into_inner();
     (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
@@ -390,19 +334,14 @@
     let (body, _) = tcx.mir_promoted(def);
     let mut body = body.steal();
 
-    run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, None);
-    check_consts::post_drop_elaboration::check_live_drops(tcx, def.did, &body);
+    run_post_borrowck_cleanup_passes(tcx, &mut body);
+    check_consts::post_drop_elaboration::check_live_drops(tcx, &body);
     tcx.alloc_steal_mir(body)
 }
 
 /// After this series of passes, no lifetime analysis based on borrowing can be done.
-fn run_post_borrowck_cleanup_passes<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &mut Body<'tcx>,
-    def_id: LocalDefId,
-    promoted: Option<Promoted>,
-) {
-    debug!("post_borrowck_cleanup({:?})", def_id);
+fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    debug!("post_borrowck_cleanup({:?})", body.source.def_id());
 
     let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
         // Remove all things only needed by analysis
@@ -427,22 +366,10 @@
         &deaggregator::Deaggregator,
     ];
 
-    run_passes(
-        tcx,
-        body,
-        InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())),
-        promoted,
-        MirPhase::DropLowering,
-        &[post_borrowck_cleanup],
-    );
+    run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]);
 }
 
-fn run_optimization_passes<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &mut Body<'tcx>,
-    def_id: LocalDefId,
-    promoted: Option<Promoted>,
-) {
+fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let mir_opt_level = tcx.sess.opts.debugging_opts.mir_opt_level;
 
     // Lowering generator control-flow and variables has to happen before we do anything else
@@ -464,6 +391,7 @@
         &remove_unneeded_drops::RemoveUnneededDrops,
         &match_branches::MatchBranchSimplification,
         // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
+        &multiple_return_terminators::MultipleReturnTerminators,
         &instcombine::InstCombine,
         &const_prop::ConstProp,
         &simplify_branches::SimplifyBranches::new("after-const-prop"),
@@ -472,12 +400,12 @@
         &simplify_try::SimplifyArmIdentity,
         &simplify_try::SimplifyBranchSame,
         &dest_prop::DestinationPropagation,
-        &copy_prop::CopyPropagation,
-        &simplify_branches::SimplifyBranches::new("after-copy-prop"),
+        &simplify_branches::SimplifyBranches::new("final"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
         &simplify::SimplifyCfg::new("final"),
         &nrvo::RenameReturnPlace,
         &simplify::SimplifyLocals,
+        &multiple_return_terminators::MultipleReturnTerminators,
     ];
 
     // Optimizations to run even if mir optimizations have been disabled.
@@ -499,8 +427,6 @@
     run_passes(
         tcx,
         body,
-        InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())),
-        promoted,
         MirPhase::GeneratorLowering,
         &[
             if mir_opt_level > 0 {
@@ -516,8 +442,6 @@
     run_passes(
         tcx,
         body,
-        InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())),
-        promoted,
         MirPhase::Optimization,
         &[
             if mir_opt_level > 0 { optimizations } else { no_optimizations },
@@ -555,7 +479,7 @@
     }
 
     let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
-    run_optimization_passes(tcx, &mut body, def.did, None);
+    run_optimization_passes(tcx, &mut body);
 
     debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
 
@@ -578,9 +502,9 @@
     let (_, promoted) = tcx.mir_promoted(def);
     let mut promoted = promoted.steal();
 
-    for (p, mut body) in promoted.iter_enumerated_mut() {
-        run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, Some(p));
-        run_optimization_passes(tcx, &mut body, def.did, Some(p));
+    for body in &mut promoted {
+        run_post_borrowck_cleanup_passes(tcx, body);
+        run_optimization_passes(tcx, body);
     }
 
     debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
new file mode 100644
index 0000000..c37b54a
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
@@ -0,0 +1,38 @@
+//! This pass removes jumps to basic blocks containing only a return, and replaces them with a
+//! return instead.
+
+use crate::transform::{simplify, MirPass};
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+pub struct MultipleReturnTerminators;
+
+impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        if tcx.sess.opts.debugging_opts.mir_opt_level < 3 {
+            return;
+        }
+
+        // find basic blocks with no statement and a return terminator
+        let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
+        let bbs = body.basic_blocks_mut();
+        for idx in bbs.indices() {
+            if bbs[idx].statements.is_empty()
+                && bbs[idx].terminator().kind == TerminatorKind::Return
+            {
+                bbs_simple_returns.insert(idx);
+            }
+        }
+
+        for bb in bbs {
+            if let TerminatorKind::Goto { target } = bb.terminator().kind {
+                if bbs_simple_returns.contains(target) {
+                    bb.terminator_mut().kind = TerminatorKind::Return;
+                }
+            }
+        }
+
+        simplify::remove_dead_blocks(body)
+    }
+}
diff --git a/compiler/rustc_mir/src/transform/no_landing_pads.rs b/compiler/rustc_mir/src/transform/no_landing_pads.rs
index 1d83733..83954c9 100644
--- a/compiler/rustc_mir/src/transform/no_landing_pads.rs
+++ b/compiler/rustc_mir/src/transform/no_landing_pads.rs
@@ -1,7 +1,7 @@
 //! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
 //! specified.
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -18,7 +18,7 @@
 }
 
 impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         no_landing_pads(tcx, body)
     }
 }
diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs
index 1ffb5a8..7e05d66 100644
--- a/compiler/rustc_mir/src/transform/nrvo.rs
+++ b/compiler/rustc_mir/src/transform/nrvo.rs
@@ -4,7 +4,7 @@
 use rustc_middle::mir::{self, BasicBlock, Local, Location};
 use rustc_middle::ty::TyCtxt;
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 
 /// This pass looks for MIR that always copies the same local into the return place and eliminates
 /// the copy by renaming all uses of that local to `_0`.
@@ -31,28 +31,22 @@
 pub struct RenameReturnPlace;
 
 impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut mir::Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
         if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
             return;
         }
 
-        if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
-            // The `DestinationPropagation` pass runs at level 2, so this pass is redundant (and
-            // fails some asserts).
-            return;
-        }
-
         let returned_local = match local_eligible_for_nrvo(body) {
             Some(l) => l,
             None => {
-                debug!("`{:?}` was ineligible for NRVO", src.def_id());
+                debug!("`{:?}` was ineligible for NRVO", body.source.def_id());
                 return;
             }
         };
 
         debug!(
             "`{:?}` was eligible for NRVO, making {:?} the return place",
-            src.def_id(),
+            body.source.def_id(),
             returned_local
         );
 
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index cd361e4..7373abc 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -32,7 +32,7 @@
 
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 
 /// A `MirPass` for promotion.
 ///
@@ -47,7 +47,7 @@
 }
 
 impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // There's not really any point in promoting errorful MIR.
         //
         // This does not include MIR that failed const-checking, which we still try to promote.
@@ -56,19 +56,17 @@
             return;
         }
 
-        if src.promoted.is_some() {
+        if body.source.promoted.is_some() {
             return;
         }
 
-        let def = src.with_opt_param().expect_local();
-
         let mut rpo = traversal::reverse_postorder(body);
-        let ccx = ConstCx::new(tcx, def.did, body);
+        let ccx = ConstCx::new(tcx, body);
         let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
 
         let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
 
-        let promoted = promote_candidates(def.to_global(), body, tcx, temps, promotable_candidates);
+        let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
         self.promoted_fragments.set(promoted);
     }
 }
@@ -126,6 +124,15 @@
             Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true,
         }
     }
+
+    fn source_info(&self, body: &Body<'_>) -> SourceInfo {
+        match self {
+            Candidate::Ref(location) | Candidate::Repeat(location) => *body.source_info(*location),
+            Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => {
+                *body.source_info(body.terminator_loc(*bb))
+            }
+        }
+    }
 }
 
 fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
@@ -137,7 +144,7 @@
             LitKind::Int(a, _) => {
                 ret.push(a as usize);
             }
-            _ => return None,
+            _ => bug!("invalid arg index"),
         }
     }
     Some(ret)
@@ -758,7 +765,7 @@
             ty::FnDef(def_id, _) => {
                 is_const_fn(self.tcx, def_id)
                     || is_unstable_const_fn(self.tcx, def_id).is_some()
-                    || is_lang_panic_fn(self.tcx, self.def_id.to_def_id())
+                    || is_lang_panic_fn(self.tcx, def_id)
             }
             _ => false,
         };
@@ -955,6 +962,7 @@
                             from_hir_call,
                             fn_span,
                         },
+                        source_info: SourceInfo::outermost(terminator.source_info.span),
                         ..terminator
                     };
                 }
@@ -970,10 +978,10 @@
 
     fn promote_candidate(
         mut self,
-        def: ty::WithOptConstParam<DefId>,
         candidate: Candidate,
         next_promoted_id: usize,
     ) -> Option<Body<'tcx>> {
+        let def = self.source.source.with_opt_param();
         let mut rvalue = {
             let promoted = &mut self.promoted;
             let promoted_id = Promoted::new(next_promoted_id);
@@ -1133,7 +1141,6 @@
 }
 
 pub fn promote_candidates<'tcx>(
-    def: ty::WithOptConstParam<DefId>,
     body: &mut Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     mut temps: IndexVec<Local, TempState>,
@@ -1166,11 +1173,13 @@
         // Declare return place local so that `mir::Body::new` doesn't complain.
         let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect();
 
+        let mut scope = body.source_scopes[candidate.source_info(body).scope].clone();
+        scope.parent_scope = None;
+
         let mut promoted = Body::new(
+            body.source, // `promoted` gets filled in below
             IndexVec::new(),
-            // FIXME: maybe try to filter this to avoid blowing up
-            // memory usage?
-            body.source_scopes.clone(),
+            IndexVec::from_elem_n(scope, 1),
             initial_locals,
             IndexVec::new(),
             0,
@@ -1190,7 +1199,8 @@
         };
 
         //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice
-        if let Some(promoted) = promoter.promote_candidate(def, candidate, promotions.len()) {
+        if let Some(mut promoted) = promoter.promote_candidate(candidate, promotions.len()) {
+            promoted.source.promoted = Some(promotions.next_index());
             promotions.push(promoted);
         }
     }
@@ -1248,7 +1258,9 @@
     debug!(
         "should_suggest_const_in_array_repeat_expressions_flag: def_id={:?} \
             should_promote={:?} feature_flag={:?}",
-        validator.ccx.def_id, should_promote, feature_flag
+        validator.ccx.def_id(),
+        should_promote,
+        feature_flag
     );
     should_promote && !feature_flag
 }
diff --git a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
index 4079f01..31e201c 100644
--- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
@@ -1,4 +1,4 @@
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use crate::util::patch::MirPatch;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
@@ -20,7 +20,7 @@
 }
 
 impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         remove_noop_landing_pads(tcx, body);
     }
 }
@@ -43,7 +43,7 @@
                     // These are all nops in a landing pad
                 }
 
-                StatementKind::Assign(box (place, Rvalue::Use(_))) => {
+                StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => {
                     if place.as_local().is_some() {
                         // Writing to a local (e.g., a drop flag) does not
                         // turn a landing pad to a non-nop
diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
index b9f2978..aaf3eca 100644
--- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
@@ -1,23 +1,22 @@
 //! This pass replaces a drop of a type that does not need dropping, with a goto
 
-use crate::transform::{MirPass, MirSource};
-use rustc_hir::def_id::LocalDefId;
+use crate::transform::MirPass;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
 
 use super::simplify::simplify_cfg;
 
 pub struct RemoveUnneededDrops;
 
 impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        trace!("Running RemoveUnneededDrops on {:?}", source);
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        trace!("Running RemoveUnneededDrops on {:?}", body.source);
         let mut opt_finder = RemoveUnneededDropsOptimizationFinder {
             tcx,
             body,
+            param_env: tcx.param_env(body.source.def_id()),
             optimizations: vec![],
-            def_id: source.def_id().expect_local(),
         };
         opt_finder.visit_body(body);
         let should_simplify = !opt_finder.optimizations.is_empty();
@@ -40,7 +39,7 @@
         match terminator.kind {
             TerminatorKind::Drop { place, target, .. } => {
                 let ty = place.ty(self.body, self.tcx);
-                let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id));
+                let needs_drop = ty.ty.needs_drop(self.tcx, self.param_env);
                 if !needs_drop {
                     self.optimizations.push((location, target));
                 }
@@ -54,5 +53,5 @@
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
     optimizations: Vec<(Location, BasicBlock)>,
-    def_id: LocalDefId,
+    param_env: ParamEnv<'tcx>,
 }
diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs
index 015af44..205f718d 100644
--- a/compiler/rustc_mir/src/transform/rustc_peek.rs
+++ b/compiler/rustc_mir/src/transform/rustc_peek.rs
@@ -5,8 +5,7 @@
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-use crate::transform::{MirPass, MirSource};
-use rustc_hir::def_id::DefId;
+use crate::transform::MirPass;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -23,9 +22,9 @@
 pub struct SanityCheck;
 
 impl<'tcx> MirPass<'tcx> for SanityCheck {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         use crate::dataflow::has_rustc_mir_with;
-        let def_id = src.def_id();
+        let def_id = body.source.def_id();
         if !tcx.has_attr(def_id, sym::rustc_mir) {
             debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
             return;
@@ -41,41 +40,40 @@
 
         if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() {
             let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
-                .into_engine(tcx, body, def_id)
+                .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits);
+            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_inits);
         }
 
         if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() {
             let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
-                .into_engine(tcx, body, def_id)
+                .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_uninits);
+            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_uninits);
         }
 
         if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() {
             let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
-                .into_engine(tcx, body, def_id)
+                .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits);
+            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits);
         }
 
         if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
             let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
-                .into_engine(tcx, body, def_id)
+                .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_mut_borrowed);
+            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed);
         }
 
         if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
-            let flow_liveness =
-                MaybeLiveLocals.into_engine(tcx, body, def_id).iterate_to_fixpoint();
+            let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_liveness);
+            sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_liveness);
         }
 
         if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() {
@@ -103,12 +101,12 @@
 pub fn sanity_check_via_rustc_peek<'tcx, A>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    def_id: DefId,
     _attributes: &[ast::Attribute],
     results: &Results<'tcx, A>,
 ) where
     A: RustcPeekAt<'tcx>,
 {
+    let def_id = body.source.def_id();
     debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);
 
     let mut cursor = ResultsCursor::new(body, results);
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index 3fc8e6d..f0c87bc 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -27,7 +27,7 @@
 //! naively generate still contains the `_a = ()` write in the unreachable block "after" the
 //! return.
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -59,7 +59,7 @@
         Cow::Borrowed(&self.label)
     }
 
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
         simplify_cfg(body);
     }
@@ -318,8 +318,8 @@
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        trace!("running SimplifyLocals on {:?}", source);
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        trace!("running SimplifyLocals on {:?}", body.source);
 
         // First, we're going to get a count of *actual* uses for every `Local`.
         // Take a look at `DeclMarker::visit_local()` to see exactly what is ignored.
diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs
index 4c30a09..5f63c03 100644
--- a/compiler/rustc_mir/src/transform/simplify_branches.rs
+++ b/compiler/rustc_mir/src/transform/simplify_branches.rs
@@ -1,6 +1,6 @@
 //! A pass that simplifies branches when their condition is known.
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
@@ -21,25 +21,24 @@
         Cow::Borrowed(&self.label)
     }
 
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(src.def_id());
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let param_env = tcx.param_env(body.source.def_id());
         for block in body.basic_blocks_mut() {
             let terminator = block.terminator_mut();
             terminator.kind = match terminator.kind {
                 TerminatorKind::SwitchInt {
                     discr: Operand::Constant(ref c),
                     switch_ty,
-                    ref values,
                     ref targets,
                     ..
                 } => {
                     let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
                     if let Some(constant) = constant {
-                        let (otherwise, targets) = targets.split_last().unwrap();
-                        let mut ret = TerminatorKind::Goto { target: *otherwise };
-                        for (&v, t) in values.iter().zip(targets.iter()) {
+                        let otherwise = targets.otherwise();
+                        let mut ret = TerminatorKind::Goto { target: otherwise };
+                        for (v, t) in targets.iter() {
                             if v == constant {
-                                ret = TerminatorKind::Goto { target: *t };
+                                ret = TerminatorKind::Goto { target: t };
                                 break;
                             }
                         }
diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
index 9b460c9..6372f89 100644
--- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
@@ -1,8 +1,10 @@
-use super::{MirPass, MirSource};
+use std::iter;
+
+use super::MirPass;
 use rustc_middle::{
     mir::{
         interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement,
-        StatementKind, TerminatorKind,
+        StatementKind, SwitchTargets, TerminatorKind,
     },
     ty::{Ty, TyCtxt},
 };
@@ -24,8 +26,8 @@
 pub struct SimplifyComparisonIntegral;
 
 impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
-    fn run_pass(&self, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        trace!("Running SimplifyComparisonIntegral on {:?}", source);
+    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        trace!("Running SimplifyComparisonIntegral on {:?}", body.source);
 
         let helper = OptimizationFinder { body };
         let opts = helper.find_optimizations();
@@ -43,19 +45,21 @@
                 Scalar::Ptr(_) => continue,
             };
             const FALSE: u128 = 0;
-            let mut new_targets = opt.targets.clone();
-            let first_is_false_target = opt.values[0] == FALSE;
+
+            let mut new_targets = opt.targets;
+            let first_value = new_targets.iter().next().unwrap().0;
+            let first_is_false_target = first_value == FALSE;
             match opt.op {
                 BinOp::Eq => {
                     // if the assignment was Eq we want the true case to be first
                     if first_is_false_target {
-                        new_targets.swap(0, 1);
+                        new_targets.all_targets_mut().swap(0, 1);
                     }
                 }
                 BinOp::Ne => {
                     // if the assignment was Ne we want the false case to be first
                     if !first_is_false_target {
-                        new_targets.swap(0, 1);
+                        new_targets.all_targets_mut().swap(0, 1);
                     }
                 }
                 _ => unreachable!(),
@@ -96,7 +100,7 @@
                 }
                 storage_deads_to_remove.push((stmt_idx, opt.bb_idx));
                 // if we have StorageDeads to remove then make sure to insert them at the top of each target
-                for bb_idx in new_targets.iter() {
+                for bb_idx in new_targets.all_targets() {
                     storage_deads_to_insert.push((
                         *bb_idx,
                         Statement {
@@ -107,13 +111,18 @@
                 }
             }
 
-            let terminator = bb.terminator_mut();
+            let [bb_cond, bb_otherwise] = match new_targets.all_targets() {
+                [a, b] => [*a, *b],
+                e => bug!("expected 2 switch targets, got: {:?}", e),
+            };
 
+            let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise);
+
+            let terminator = bb.terminator_mut();
             terminator.kind = TerminatorKind::SwitchInt {
                 discr: Operand::Move(opt.to_switch_on),
                 switch_ty: opt.branch_value_ty,
-                values: vec![new_value].into(),
-                targets: new_targets,
+                targets,
             };
         }
 
@@ -138,15 +147,13 @@
             .iter_enumerated()
             .filter_map(|(bb_idx, bb)| {
                 // find switch
-                let (place_switched_on, values, targets, place_switched_on_moved) = match &bb
-                    .terminator()
-                    .kind
-                {
-                    rustc_middle::mir::TerminatorKind::SwitchInt {
-                        discr, values, targets, ..
-                    } => Some((discr.place()?, values, targets, discr.is_move())),
-                    _ => None,
-                }?;
+                let (place_switched_on, targets, place_switched_on_moved) =
+                    match &bb.terminator().kind {
+                        rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => {
+                            Some((discr.place()?, targets, discr.is_move()))
+                        }
+                        _ => None,
+                    }?;
 
                 // find the statement that assigns the place being switched on
                 bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| {
@@ -167,7 +174,6 @@
                                         branch_value_scalar,
                                         branch_value_ty,
                                         op: *op,
-                                        values: values.clone().into_owned(),
                                         targets: targets.clone(),
                                     })
                                 }
@@ -220,8 +226,6 @@
     branch_value_ty: Ty<'tcx>,
     /// Either Eq or Ne
     op: BinOp,
-    /// Current values used in the switch target. This needs to be replaced with the branch_value
-    values: Vec<u128>,
     /// Current targets used in the switch
-    targets: Vec<BasicBlock>,
+    targets: SwitchTargets,
 }
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index 4935997..27bb1de 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -9,7 +9,7 @@
 //!
 //! into just `x`.
 
-use crate::transform::{simplify, MirPass, MirSource};
+use crate::transform::{simplify, MirPass};
 use itertools::Itertools as _;
 use rustc_index::{bit_set::BitSet, vec::IndexVec};
 use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
@@ -367,8 +367,15 @@
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        // FIXME(77359): This optimization can result in unsoundness.
+        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
+            return;
+        }
+
+        let source = body.source;
         trace!("running SimplifyArmIdentity on {:?}", source);
+
         let local_uses = LocalUseCounter::get_local_uses(body);
         let (basic_blocks, local_decls, debug_info) =
             body.basic_blocks_local_decls_mut_and_var_debug_info();
@@ -523,8 +530,8 @@
 pub struct SimplifyBranchSame;
 
 impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        trace!("Running SimplifyBranchSame on {:?}", source);
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        trace!("Running SimplifyBranchSame on {:?}", body.source);
         let finder = SimplifyBranchSameOptimizationFinder { body, tcx };
         let opts = finder.find();
 
@@ -569,15 +576,13 @@
             .iter_enumerated()
             .filter_map(|(bb_idx, bb)| {
                 let (discr_switched_on, targets_and_values) = match &bb.terminator().kind {
-                    TerminatorKind::SwitchInt { targets, discr, values, .. } => {
-                        // if values.len() == targets.len() - 1, we need to include None where no value is present
-                        // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None
-                        let values_extended = values.iter().map(|x|Some(*x)).chain(once(None));
-                        let targets_and_values:Vec<_> = targets.iter().zip(values_extended)
-                            .map(|(target, value)| SwitchTargetAndValue{target:*target, value})
+                    TerminatorKind::SwitchInt { targets, discr, .. } => {
+                        let targets_and_values: Vec<_> = targets.iter()
+                            .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) })
+                            .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None }))
                             .collect();
-                        assert_eq!(targets.len(), targets_and_values.len());
-                        (discr, targets_and_values)},
+                        (discr, targets_and_values)
+                    },
                     _ => return None,
                 };
 
@@ -623,7 +628,8 @@
                 // All successor basic blocks must be equal or contain statements that are pairwise considered equal.
                 for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() {
                     let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup
-                    && bb_l.terminator().kind == bb_r.terminator().kind;
+                                            && bb_l.terminator().kind == bb_r.terminator().kind
+                                            && bb_l.statements.len() == bb_r.statements.len();
                     let statement_check = || {
                         bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| {
                             let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r);
diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
index 4cca4d2..465832c 100644
--- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
@@ -1,8 +1,10 @@
 //! A pass that eliminates branches on uninhabited enum variants.
 
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_middle::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind,
+    BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets,
+    TerminatorKind,
 };
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -52,9 +54,13 @@
     layout: &TyAndLayout<'tcx>,
     ty: Ty<'tcx>,
     tcx: TyCtxt<'tcx>,
-) -> Vec<u128> {
+) -> FxHashSet<u128> {
     match &layout.variants {
-        Variants::Single { index } => vec![index.as_u32() as u128],
+        Variants::Single { index } => {
+            let mut res = FxHashSet::default();
+            res.insert(index.as_u32() as u128);
+            res
+        }
         Variants::Multiple { variants, .. } => variants
             .iter_enumerated()
             .filter_map(|(idx, layout)| {
@@ -66,12 +72,12 @@
 }
 
 impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        if source.promoted.is_some() {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        if body.source.promoted.is_some() {
             return;
         }
 
-        trace!("UninhabitedEnumBranching starting for {:?}", source);
+        trace!("UninhabitedEnumBranching starting for {:?}", body.source);
 
         let basic_block_count = body.basic_blocks().len();
 
@@ -86,7 +92,7 @@
                     continue;
                 };
 
-            let layout = tcx.layout_of(tcx.param_env(source.def_id()).and(discriminant_ty));
+            let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty));
 
             let allowed_variants = if let Ok(layout) = layout {
                 variant_discriminants(&layout, discriminant_ty, tcx)
@@ -96,21 +102,15 @@
 
             trace!("allowed_variants = {:?}", allowed_variants);
 
-            if let TerminatorKind::SwitchInt { values, targets, .. } =
+            if let TerminatorKind::SwitchInt { targets, .. } =
                 &mut body.basic_blocks_mut()[bb].terminator_mut().kind
             {
-                // take otherwise out early
-                let otherwise = targets.pop().unwrap();
-                assert_eq!(targets.len(), values.len());
-                let mut i = 0;
-                targets.retain(|_| {
-                    let keep = allowed_variants.contains(&values[i]);
-                    i += 1;
-                    keep
-                });
-                targets.push(otherwise);
+                let new_targets = SwitchTargets::new(
+                    targets.iter().filter(|(val, _)| allowed_variants.contains(val)),
+                    targets.otherwise(),
+                );
 
-                values.to_mut().retain(|var| allowed_variants.contains(var));
+                *targets = new_targets;
             } else {
                 unreachable!()
             }
diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs
index fa362c6..f6d39da 100644
--- a/compiler/rustc_mir/src/transform/unreachable_prop.rs
+++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs
@@ -3,16 +3,15 @@
 //! post-order traversal of the blocks.
 
 use crate::transform::simplify;
-use crate::transform::{MirPass, MirSource};
+use crate::transform::MirPass;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
-use std::borrow::Cow;
 
 pub struct UnreachablePropagation;
 
 impl MirPass<'_> for UnreachablePropagation {
-    fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if tcx.sess.opts.debugging_opts.mir_opt_level < 3 {
             // Enable only under -Zmir-opt-level=3 as in some cases (check the deeply-nested-opt
             // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
@@ -69,14 +68,15 @@
 {
     let terminator = match *terminator_kind {
         TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable,
-        TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
-            let original_targets_len = targets.len();
-            let (otherwise, targets) = targets.split_last().unwrap();
-            let (mut values, mut targets): (Vec<_>, Vec<_>) =
-                values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip();
+        TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
+            let otherwise = targets.otherwise();
 
-            if !predicate(*otherwise) {
-                targets.push(*otherwise);
+            let original_targets_len = targets.iter().len() + 1;
+            let (mut values, mut targets): (Vec<_>, Vec<_>) =
+                targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip();
+
+            if !predicate(otherwise) {
+                targets.push(otherwise);
             } else {
                 values.pop();
             }
@@ -91,8 +91,10 @@
                 TerminatorKind::SwitchInt {
                     discr: discr.clone(),
                     switch_ty,
-                    values: Cow::from(values),
-                    targets,
+                    targets: SwitchTargets::new(
+                        values.iter().copied().zip(targets.iter().copied()),
+                        *targets.last().unwrap(),
+                    ),
                 }
             } else {
                 return None;
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs
index d3ca14a..beffffa 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -1,18 +1,17 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
-use super::{MirPass, MirSource};
-use rustc_middle::mir::visit::Visitor;
-use rustc_middle::{
-    mir::{
-        AggregateKind, BasicBlock, Body, BorrowKind, Location, MirPhase, Operand, Rvalue,
-        Statement, StatementKind, Terminator, TerminatorKind,
-    },
-    ty::{
-        self,
-        relate::{Relate, RelateResult, TypeRelation},
-        ParamEnv, Ty, TyCtxt,
-    },
+use crate::dataflow::impls::MaybeStorageLive;
+use crate::dataflow::{Analysis, ResultsCursor};
+use crate::util::storage::AlwaysLiveLocals;
+
+use super::MirPass;
+use rustc_middle::mir::visit::{PlaceContext, Visitor};
+use rustc_middle::mir::{
+    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue,
+    SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo,
 };
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug)]
 enum EdgeKind {
@@ -32,10 +31,19 @@
 }
 
 impl<'tcx> MirPass<'tcx> for Validator {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(source.def_id());
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let def_id = body.source.def_id();
+        let param_env = tcx.param_env(def_id);
         let mir_phase = self.mir_phase;
-        TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase }.visit_body(body);
+
+        let always_live_locals = AlwaysLiveLocals::new(body);
+        let storage_liveness = MaybeStorageLive::new(always_live_locals)
+            .into_engine(tcx, body)
+            .iterate_to_fixpoint()
+            .into_results_cursor(body);
+
+        TypeChecker { when: &self.when, body, tcx, param_env, mir_phase, storage_liveness }
+            .visit_body(body);
     }
 }
 
@@ -133,11 +141,11 @@
 
 struct TypeChecker<'a, 'tcx> {
     when: &'a str,
-    source: MirSource<'tcx>,
     body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
     mir_phase: MirPhase,
+    storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>,
 }
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
@@ -149,7 +157,7 @@
             span,
             &format!(
                 "broken MIR in {:?} ({}) at {:?}:\n{}",
-                self.source.instance,
+                self.body.source.instance,
                 self.when,
                 location,
                 msg.as_ref()
@@ -210,6 +218,23 @@
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
+    fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
+        if context.is_use() {
+            // Uses of locals must occur while the local's storage is allocated.
+            self.storage_liveness.seek_after_primary_effect(location);
+            let locals_with_storage = self.storage_liveness.get();
+            if !locals_with_storage.contains(*local) {
+                self.fail(location, format!("use of local {:?}, which has no storage here", local));
+            }
+        }
+    }
+
+    fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) {
+        // Debuginfo can contain field projections, which count as a use of the base local. Skip
+        // debuginfo so that we avoid the storage liveness assertion in that case.
+        self.visit_source_info(&var_debug_info.source_info);
+    }
+
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         // `Operand::Copy` is only supposed to be used with `Copy` types.
         if let Operand::Copy(place) = operand {
@@ -310,7 +335,7 @@
             TerminatorKind::Goto { target } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
             }
-            TerminatorKind::SwitchInt { targets, values, switch_ty, discr } => {
+            TerminatorKind::SwitchInt { targets, switch_ty, discr } => {
                 let ty = discr.ty(&self.body.local_decls, self.tcx);
                 if ty != *switch_ty {
                     self.fail(
@@ -321,19 +346,10 @@
                         ),
                     );
                 }
-                if targets.len() != values.len() + 1 {
-                    self.fail(
-                        location,
-                        format!(
-                            "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)",
-                            values.len(),
-                            targets.len(),
-                        ),
-                    );
+                for (_, target) in targets.iter() {
+                    self.check_edge(location, target, EdgeKind::Normal);
                 }
-                for target in targets {
-                    self.check_edge(location, *target, EdgeKind::Normal);
-                }
+                self.check_edge(location, targets.otherwise(), EdgeKind::Normal);
             }
             TerminatorKind::Drop { target, unwind, .. } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
@@ -417,4 +433,16 @@
             | TerminatorKind::GeneratorDrop => {}
         }
     }
+
+    fn visit_source_scope(&mut self, scope: &SourceScope) {
+        if self.body.source_scopes.get(*scope).is_none() {
+            self.tcx.sess.diagnostic().delay_span_bug(
+                self.body.span,
+                &format!(
+                    "broken MIR in {:?} ({}):\ninvalid source scope {:?}",
+                    self.body.source.instance, self.when, scope,
+                ),
+            );
+        }
+    }
 }
diff --git a/compiler/rustc_mir/src/util/def_use.rs b/compiler/rustc_mir/src/util/def_use.rs
deleted file mode 100644
index b4448ea..0000000
--- a/compiler/rustc_mir/src/util/def_use.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! Def-use analysis.
-
-use rustc_index::vec::IndexVec;
-use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
-use rustc_middle::mir::{Body, Local, Location, VarDebugInfo};
-use rustc_middle::ty::TyCtxt;
-use std::mem;
-
-pub struct DefUseAnalysis {
-    info: IndexVec<Local, Info>,
-}
-
-#[derive(Clone)]
-pub struct Info {
-    // FIXME(eddyb) use smallvec where possible.
-    pub defs_and_uses: Vec<Use>,
-    var_debug_info_indices: Vec<usize>,
-}
-
-#[derive(Clone)]
-pub struct Use {
-    pub context: PlaceContext,
-    pub location: Location,
-}
-
-impl DefUseAnalysis {
-    pub fn new(body: &Body<'_>) -> DefUseAnalysis {
-        DefUseAnalysis { info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()) }
-    }
-
-    pub fn analyze(&mut self, body: &Body<'_>) {
-        self.clear();
-
-        let mut finder = DefUseFinder {
-            info: mem::take(&mut self.info),
-            var_debug_info_index: 0,
-            in_var_debug_info: false,
-        };
-        finder.visit_body(&body);
-        self.info = finder.info
-    }
-
-    fn clear(&mut self) {
-        for info in &mut self.info {
-            info.clear();
-        }
-    }
-
-    pub fn local_info(&self, local: Local) -> &Info {
-        &self.info[local]
-    }
-
-    fn mutate_defs_and_uses(
-        &self,
-        local: Local,
-        body: &mut Body<'tcx>,
-        new_local: Local,
-        tcx: TyCtxt<'tcx>,
-    ) {
-        let mut visitor = MutateUseVisitor::new(local, new_local, tcx);
-        let info = &self.info[local];
-        for place_use in &info.defs_and_uses {
-            visitor.visit_location(body, place_use.location)
-        }
-        // Update debuginfo as well, alongside defs/uses.
-        for &i in &info.var_debug_info_indices {
-            visitor.visit_var_debug_info(&mut body.var_debug_info[i]);
-        }
-    }
-
-    // FIXME(pcwalton): this should update the def-use chains.
-    pub fn replace_all_defs_and_uses_with(
-        &self,
-        local: Local,
-        body: &mut Body<'tcx>,
-        new_local: Local,
-        tcx: TyCtxt<'tcx>,
-    ) {
-        self.mutate_defs_and_uses(local, body, new_local, tcx)
-    }
-}
-
-struct DefUseFinder {
-    info: IndexVec<Local, Info>,
-    var_debug_info_index: usize,
-    in_var_debug_info: bool,
-}
-
-impl Visitor<'_> for DefUseFinder {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
-        let info = &mut self.info[local];
-        if self.in_var_debug_info {
-            info.var_debug_info_indices.push(self.var_debug_info_index);
-        } else {
-            info.defs_and_uses.push(Use { context, location });
-        }
-    }
-    fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) {
-        assert!(!self.in_var_debug_info);
-        self.in_var_debug_info = true;
-        self.super_var_debug_info(var_debug_info);
-        self.in_var_debug_info = false;
-        self.var_debug_info_index += 1;
-    }
-}
-
-impl Info {
-    fn new() -> Info {
-        Info { defs_and_uses: vec![], var_debug_info_indices: vec![] }
-    }
-
-    fn clear(&mut self) {
-        self.defs_and_uses.clear();
-        self.var_debug_info_indices.clear();
-    }
-
-    pub fn def_count(&self) -> usize {
-        self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
-    }
-
-    pub fn def_count_not_including_drop(&self) -> usize {
-        self.defs_not_including_drop().count()
-    }
-
-    pub fn defs_not_including_drop(&self) -> impl Iterator<Item = &Use> {
-        self.defs_and_uses
-            .iter()
-            .filter(|place_use| place_use.context.is_mutating_use() && !place_use.context.is_drop())
-    }
-
-    pub fn use_count(&self) -> usize {
-        self.defs_and_uses.iter().filter(|place_use| place_use.context.is_nonmutating_use()).count()
-    }
-}
-
-struct MutateUseVisitor<'tcx> {
-    query: Local,
-    new_local: Local,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl MutateUseVisitor<'tcx> {
-    fn new(query: Local, new_local: Local, tcx: TyCtxt<'tcx>) -> MutateUseVisitor<'tcx> {
-        MutateUseVisitor { query, new_local, tcx }
-    }
-}
-
-impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, local: &mut Local, _context: PlaceContext, _location: Location) {
-        if *local == self.query {
-            *local = self.new_local;
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs
index bf0a6be..0e2d8e5 100644
--- a/compiler/rustc_mir/src/util/elaborate_drops.rs
+++ b/compiler/rustc_mir/src/util/elaborate_drops.rs
@@ -231,8 +231,6 @@
                     .patch_terminator(bb, TerminatorKind::Goto { target: self.succ });
             }
             DropStyle::Static => {
-                let loc = self.terminator_loc(bb);
-                self.elaborator.clear_drop_flag(loc, self.path, DropFlagMode::Deep);
                 self.elaborator.patch().patch_terminator(
                     bb,
                     TerminatorKind::Drop {
@@ -243,9 +241,7 @@
                 );
             }
             DropStyle::Conditional => {
-                let unwind = self.unwind; // FIXME(#43234)
-                let succ = self.succ;
-                let drop_bb = self.complete_drop(Some(DropFlagMode::Deep), succ, unwind);
+                let drop_bb = self.complete_drop(self.succ, self.unwind);
                 self.elaborator
                     .patch()
                     .patch_terminator(bb, TerminatorKind::Goto { target: drop_bb });
@@ -317,7 +313,7 @@
                 // our own drop flag.
                 path: self.path,
             }
-            .complete_drop(None, succ, unwind)
+            .complete_drop(succ, unwind)
         }
     }
 
@@ -346,13 +342,7 @@
         // Clear the "master" drop flag at the end. This is needed
         // because the "master" drop protects the ADT's discriminant,
         // which is invalidated after the ADT is dropped.
-        let (succ, unwind) = (self.succ, self.unwind); // FIXME(#43234)
-        (
-            self.drop_flag_reset_block(DropFlagMode::Shallow, succ, unwind),
-            unwind.map(|unwind| {
-                self.drop_flag_reset_block(DropFlagMode::Shallow, unwind, Unwind::InCleanup)
-            }),
-        )
+        (self.drop_flag_reset_block(DropFlagMode::Shallow, self.succ, self.unwind), self.unwind)
     }
 
     /// Creates a full drop ladder, consisting of 2 connected half-drop-ladders
@@ -598,8 +588,10 @@
                 kind: TerminatorKind::SwitchInt {
                     discr: Operand::Move(discr),
                     switch_ty: discr_ty,
-                    values: From::from(values.to_owned()),
-                    targets: blocks,
+                    targets: SwitchTargets::new(
+                        values.iter().copied().zip(blocks.iter().copied()),
+                        *blocks.last().unwrap(),
+                    ),
                 },
             }),
             is_cleanup: unwind.is_cleanup(),
@@ -768,8 +760,6 @@
         let elem_size = Place::from(self.new_temp(tcx.types.usize));
         let len = Place::from(self.new_temp(tcx.types.usize));
 
-        static USIZE_SWITCH_ZERO: &[u128] = &[0];
-
         let base_block = BasicBlockData {
             statements: vec![
                 self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
@@ -781,11 +771,11 @@
                 kind: TerminatorKind::SwitchInt {
                     discr: move_(elem_size),
                     switch_ty: tcx.types.usize,
-                    values: From::from(USIZE_SWITCH_ZERO),
-                    targets: vec![
+                    targets: SwitchTargets::static_if(
+                        0,
                         self.drop_loop_pair(ety, false, len),
                         self.drop_loop_pair(ety, true, len),
-                    ],
+                    ),
                 },
             }),
         };
@@ -884,11 +874,7 @@
                     self.open_drop_for_adt(def, substs)
                 }
             }
-            ty::Dynamic(..) => {
-                let unwind = self.unwind; // FIXME(#43234)
-                let succ = self.succ;
-                self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
-            }
+            ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
             ty::Array(ety, size) => {
                 let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env());
                 self.open_drop_for_array(ety, size)
@@ -899,20 +885,10 @@
         }
     }
 
-    fn complete_drop(
-        &mut self,
-        drop_mode: Option<DropFlagMode>,
-        succ: BasicBlock,
-        unwind: Unwind,
-    ) -> BasicBlock {
-        debug!("complete_drop({:?},{:?})", self, drop_mode);
+    fn complete_drop(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock {
+        debug!("complete_drop(succ={:?}, unwind={:?})", succ, unwind);
 
         let drop_block = self.drop_block(succ, unwind);
-        let drop_block = if let Some(mode) = drop_mode {
-            self.drop_flag_reset_block(mode, drop_block, unwind)
-        } else {
-            drop_block
-        };
 
         self.drop_flag_test_block(drop_block, succ, unwind)
     }
@@ -927,6 +903,11 @@
     ) -> BasicBlock {
         debug!("drop_flag_reset_block({:?},{:?})", self, mode);
 
+        if unwind.is_cleanup() {
+            // The drop flag isn't read again on the unwind path, so don't
+            // bother setting it.
+            return succ;
+        }
         let block = self.new_block(unwind, TerminatorKind::Goto { target: succ });
         let block_start = Location { block, statement_index: 0 };
         self.elaborator.clear_drop_flag(block_start, self.path, mode);
@@ -1044,11 +1025,6 @@
         self.elaborator.patch().new_temp(ty, self.source_info.span)
     }
 
-    fn terminator_loc(&mut self, bb: BasicBlock) -> Location {
-        let body = self.elaborator.body();
-        self.elaborator.patch().terminator_loc(body, bb)
-    }
-
     fn constant_usize(&self, val: u16) -> Operand<'tcx> {
         Operand::Constant(box Constant {
             span: self.source_info.span,
diff --git a/compiler/rustc_mir/src/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs
index 4511962..e04f077 100644
--- a/compiler/rustc_mir/src/util/graphviz.rs
+++ b/compiler/rustc_mir/src/util/graphviz.rs
@@ -22,7 +22,7 @@
 
     for def_id in def_ids {
         let body = &tcx.optimized_mir(def_id);
-        write_mir_fn_graphviz(tcx, def_id, body, use_subgraphs, w)?;
+        write_mir_fn_graphviz(tcx, body, use_subgraphs, w)?;
     }
 
     if use_subgraphs {
@@ -41,7 +41,6 @@
 /// Write a graphviz DOT graph of the MIR.
 pub fn write_mir_fn_graphviz<'tcx, W>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
     body: &Body<'_>,
     subgraph: bool,
     w: &mut W,
@@ -49,6 +48,7 @@
 where
     W: Write,
 {
+    let def_id = body.source.def_id();
     let kind = if subgraph { "subgraph" } else { "digraph" };
     let cluster = if subgraph { "cluster_" } else { "" }; // Prints a border around MIR
     let def_name = graphviz_safe_def_name(def_id);
@@ -72,16 +72,16 @@
     writeln!(w, r#"    edge [{}];"#, content_attrs_str)?;
 
     // Graph label
-    write_graph_label(tcx, def_id, body, w)?;
+    write_graph_label(tcx, body, w)?;
 
     // Nodes
     for (block, _) in body.basic_blocks().iter_enumerated() {
-        write_node(def_id, block, body, dark_mode, w)?;
+        write_node(block, body, dark_mode, w)?;
     }
 
     // Edges
     for (source, _) in body.basic_blocks().iter_enumerated() {
-        write_edges(def_id, source, body, w)?;
+        write_edges(source, body, w)?;
     }
     writeln!(w, "}}")
 }
@@ -111,13 +111,19 @@
     write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#)?;
 
     // Basic block number at the top.
+    let (blk, bgcolor) = if data.is_cleanup {
+        (format!("{} (cleanup)", block.index()), "lightblue")
+    } else {
+        let color = if dark_mode { "dimgray" } else { "gray" };
+        (format!("{}", block.index()), color)
+    };
     write!(
         w,
         r#"<tr><td bgcolor="{bgcolor}" {attrs} colspan="{colspan}">{blk}</td></tr>"#,
-        bgcolor = if dark_mode { "dimgray" } else { "gray" },
         attrs = r#"align="center""#,
         colspan = num_cols,
-        blk = block.index()
+        blk = blk,
+        bgcolor = bgcolor
     )?;
 
     init(w)?;
@@ -145,12 +151,12 @@
 
 /// Write a graphviz DOT node for the given basic block.
 fn write_node<W: Write>(
-    def_id: DefId,
     block: BasicBlock,
     body: &Body<'_>,
     dark_mode: bool,
     w: &mut W,
 ) -> io::Result<()> {
+    let def_id = body.source.def_id();
     // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
     write!(w, r#"    {} [shape="none", label=<"#, node(def_id, block))?;
     write_node_label(block, body, dark_mode, w, 1, |_| Ok(()), |_| Ok(()))?;
@@ -159,12 +165,8 @@
 }
 
 /// Write graphviz DOT edges with labels between the given basic block and all of its successors.
-fn write_edges<W: Write>(
-    def_id: DefId,
-    source: BasicBlock,
-    body: &Body<'_>,
-    w: &mut W,
-) -> io::Result<()> {
+fn write_edges<W: Write>(source: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> {
+    let def_id = body.source.def_id();
     let terminator = body[source].terminator();
     let labels = terminator.kind.fmt_successor_labels();
 
@@ -182,10 +184,11 @@
 /// all the variables and temporaries.
 fn write_graph_label<'tcx, W: Write>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
     body: &Body<'_>,
     w: &mut W,
 ) -> io::Result<()> {
+    let def_id = body.source.def_id();
+
     write!(w, "    label=<fn {}(", dot::escape_html(&tcx.def_path_str(def_id)))?;
 
     // fn argument types.
diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs
index 699f3bc..7da2f4f 100644
--- a/compiler/rustc_mir/src/util/mod.rs
+++ b/compiler/rustc_mir/src/util/mod.rs
@@ -1,6 +1,5 @@
 pub mod aggregate;
 pub mod borrowck_errors;
-pub mod def_use;
 pub mod elaborate_drops;
 pub mod patch;
 pub mod storage;
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 49c644a..bd7c25b 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -75,17 +75,16 @@
     pass_num: Option<&dyn Display>,
     pass_name: &str,
     disambiguator: &dyn Display,
-    source: MirSource<'tcx>,
     body: &Body<'tcx>,
     extra_data: F,
 ) where
     F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
 {
-    if !dump_enabled(tcx, pass_name, source.def_id()) {
+    if !dump_enabled(tcx, pass_name, body.source.def_id()) {
         return;
     }
 
-    dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, source, body, extra_data);
+    dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data);
 }
 
 pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) -> bool {
@@ -113,20 +112,20 @@
     pass_num: Option<&dyn Display>,
     pass_name: &str,
     disambiguator: &dyn Display,
-    source: MirSource<'tcx>,
     body: &Body<'tcx>,
     mut extra_data: F,
 ) where
     F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
 {
     let _: io::Result<()> = try {
-        let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?;
+        let mut file =
+            create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body.source)?;
         let def_path = ty::print::with_forced_impl_filename_line(|| {
             // see notes on #41697 above
-            tcx.def_path_str(source.def_id())
+            tcx.def_path_str(body.source.def_id())
         });
         write!(file, "// MIR for `{}", def_path)?;
-        match source.promoted {
+        match body.source.promoted {
             None => write!(file, "`")?,
             Some(promoted) => write!(file, "::{:?}`", promoted)?,
         }
@@ -137,40 +136,39 @@
         writeln!(file)?;
         extra_data(PassWhere::BeforeCFG, &mut file)?;
         write_user_type_annotations(tcx, body, &mut file)?;
-        write_mir_fn(tcx, source, body, &mut extra_data, &mut file)?;
+        write_mir_fn(tcx, body, &mut extra_data, &mut file)?;
         extra_data(PassWhere::AfterCFG, &mut file)?;
     };
 
     if tcx.sess.opts.debugging_opts.dump_mir_graphviz {
         let _: io::Result<()> = try {
             let mut file =
-                create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
-            write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?;
+                create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body.source)?;
+            write_mir_fn_graphviz(tcx, body, false, &mut file)?;
         };
     }
 
     if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview {
         let _: io::Result<()> = try {
-            let mut file =
-                create_dump_file(tcx, "html", pass_num, pass_name, disambiguator, source)?;
-            if source.def_id().is_local() {
-                write_mir_fn_spanview(tcx, source.def_id(), body, spanview, &mut file)?;
+            let file_basename =
+                dump_file_basename(tcx, pass_num, pass_name, disambiguator, body.source);
+            let mut file = create_dump_file_with_basename(tcx, &file_basename, "html")?;
+            if body.source.def_id().is_local() {
+                write_mir_fn_spanview(tcx, body, spanview, &file_basename, &mut file)?;
             }
         };
     }
 }
 
-/// Returns the path to the filename where we should dump a given MIR.
-/// Also used by other bits of code (e.g., NLL inference) that dump
-/// graphviz data or other things.
-fn dump_path(
+/// Returns the file basename portion (without extension) of a filename path
+/// where we should dump a MIR representation output files.
+fn dump_file_basename(
     tcx: TyCtxt<'_>,
-    extension: &str,
     pass_num: Option<&dyn Display>,
     pass_name: &str,
     disambiguator: &dyn Display,
     source: MirSource<'tcx>,
-) -> PathBuf {
+) -> String {
     let promotion_id = match source.promoted {
         Some(id) => format!("-{:?}", id),
         None => String::new(),
@@ -185,9 +183,6 @@
         }
     };
 
-    let mut file_path = PathBuf::new();
-    file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir));
-
     let crate_name = tcx.crate_name(source.def_id().krate);
     let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate();
     // All drop shims have the same DefId, so we have to add the type
@@ -207,23 +202,46 @@
         _ => String::new(),
     };
 
-    let file_name = format!(
-        "{}.{}{}{}{}.{}.{}.{}",
-        crate_name,
-        item_name,
-        shim_disambiguator,
-        promotion_id,
-        pass_num,
-        pass_name,
-        disambiguator,
-        extension,
-    );
+    format!(
+        "{}.{}{}{}{}.{}.{}",
+        crate_name, item_name, shim_disambiguator, promotion_id, pass_num, pass_name, disambiguator,
+    )
+}
+
+/// Returns the path to the filename where we should dump a given MIR.
+/// Also used by other bits of code (e.g., NLL inference) that dump
+/// graphviz data or other things.
+fn dump_path(tcx: TyCtxt<'_>, basename: &str, extension: &str) -> PathBuf {
+    let mut file_path = PathBuf::new();
+    file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir));
+
+    let file_name = format!("{}.{}", basename, extension,);
 
     file_path.push(&file_name);
 
     file_path
 }
 
+/// Attempts to open the MIR dump file with the given name and extension.
+fn create_dump_file_with_basename(
+    tcx: TyCtxt<'_>,
+    file_basename: &str,
+    extension: &str,
+) -> io::Result<io::BufWriter<fs::File>> {
+    let file_path = dump_path(tcx, file_basename, extension);
+    if let Some(parent) = file_path.parent() {
+        fs::create_dir_all(parent).map_err(|e| {
+            io::Error::new(
+                e.kind(),
+                format!("IO error creating MIR dump directory: {:?}; {}", parent, e),
+            )
+        })?;
+    }
+    Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| {
+        io::Error::new(e.kind(), format!("IO error creating MIR dump file: {:?}; {}", file_path, e))
+    })?))
+}
+
 /// Attempts to open a file where we should dump a given MIR or other
 /// bit of MIR-related data. Used by `mir-dump`, but also by other
 /// bits of code (e.g., NLL inference) that dump graphviz data or
@@ -236,11 +254,11 @@
     disambiguator: &dyn Display,
     source: MirSource<'tcx>,
 ) -> io::Result<io::BufWriter<fs::File>> {
-    let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, source);
-    if let Some(parent) = file_path.parent() {
-        fs::create_dir_all(parent)?;
-    }
-    Ok(io::BufWriter::new(fs::File::create(&file_path)?))
+    create_dump_file_with_basename(
+        tcx,
+        &dump_file_basename(tcx, pass_num, pass_name, disambiguator, source),
+        extension,
+    )
 }
 
 /// Write out a human-readable textual representation for the given MIR.
@@ -263,15 +281,11 @@
             writeln!(w)?;
         }
 
-        write_mir_fn(tcx, MirSource::item(def_id), body, &mut |_, _| Ok(()), w)?;
+        write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
 
-        for (i, body) in tcx.promoted_mir(def_id).iter_enumerated() {
+        for body in tcx.promoted_mir(def_id) {
             writeln!(w)?;
-            let src = MirSource {
-                instance: ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
-                promoted: Some(i),
-            };
-            write_mir_fn(tcx, src, body, &mut |_, _| Ok(()), w)?;
+            write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
         }
     }
     Ok(())
@@ -280,7 +294,6 @@
 /// Write out a human-readable textual representation for the given function.
 pub fn write_mir_fn<'tcx, F>(
     tcx: TyCtxt<'tcx>,
-    src: MirSource<'tcx>,
     body: &Body<'tcx>,
     extra_data: &mut F,
     w: &mut dyn Write,
@@ -288,7 +301,7 @@
 where
     F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
 {
-    write_mir_intro(tcx, src, body, w)?;
+    write_mir_intro(tcx, body, w)?;
     for block in body.basic_blocks().indices() {
         extra_data(PassWhere::BeforeBlock(block), w)?;
         write_basic_block(tcx, block, body, extra_data, w)?;
@@ -548,11 +561,10 @@
 /// local variables (both user-defined bindings and compiler temporaries).
 pub fn write_mir_intro<'tcx>(
     tcx: TyCtxt<'tcx>,
-    src: MirSource<'tcx>,
     body: &Body<'_>,
     w: &mut dyn Write,
 ) -> io::Result<()> {
-    write_mir_sig(tcx, src, body, w)?;
+    write_mir_sig(tcx, body, w)?;
     writeln!(w, "{{")?;
 
     // construct a scope tree and write it out
@@ -659,7 +671,8 @@
 /// Dumps the size and metadata and content of an allocation to the given writer.
 /// The expectation is that the caller first prints other relevant metadata, so the exact
 /// format of this function is (*without* leading or trailing newline):
-/// ```
+///
+/// ```text
 /// size: {}, align: {}) {
 ///     <bytes>
 /// }
@@ -850,25 +863,21 @@
     Ok(())
 }
 
-fn write_mir_sig(
-    tcx: TyCtxt<'_>,
-    src: MirSource<'tcx>,
-    body: &Body<'_>,
-    w: &mut dyn Write,
-) -> io::Result<()> {
+fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Result<()> {
     use rustc_hir::def::DefKind;
 
-    trace!("write_mir_sig: {:?}", src.instance);
-    let kind = tcx.def_kind(src.def_id());
+    trace!("write_mir_sig: {:?}", body.source.instance);
+    let def_id = body.source.def_id();
+    let kind = tcx.def_kind(def_id);
     let is_function = match kind {
         DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
-        _ => tcx.is_closure(src.def_id()),
+        _ => tcx.is_closure(def_id),
     };
-    match (kind, src.promoted) {
+    match (kind, body.source.promoted) {
         (_, Some(i)) => write!(w, "{:?} in ", i)?,
         (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
         (DefKind::Static, _) => {
-            write!(w, "static {}", if tcx.is_mutable_static(src.def_id()) { "mut " } else { "" })?
+            write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
         }
         (_, _) if is_function => write!(w, "fn ")?,
         (DefKind::AnonConst, _) => {} // things like anon const, not an item
@@ -877,10 +886,10 @@
 
     ty::print::with_forced_impl_filename_line(|| {
         // see notes on #41697 elsewhere
-        write!(w, "{}", tcx.def_path_str(src.def_id()))
+        write!(w, "{}", tcx.def_path_str(def_id))
     })?;
 
-    if src.promoted.is_none() && is_function {
+    if body.source.promoted.is_none() && is_function {
         write!(w, "(")?;
 
         // fn argument types.
diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs
index fe33fff..d3ef8c6 100644
--- a/compiler/rustc_mir/src/util/spanview.rs
+++ b/compiler/rustc_mir/src/util/spanview.rs
@@ -16,9 +16,13 @@
 const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">";
 const HEADER: &str = r#"<!DOCTYPE html>
 <html>
-<head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
+<head>"#;
+const START_BODY: &str = r#"</head>
+<body>"#;
+const FOOTER: &str = r#"</body>
+</html>"#;
+
+const STYLE_SECTION: &str = r#"<style>
     .line {
         counter-increment: line;
     }
@@ -72,16 +76,12 @@
         /* requires hover over a span ONLY on its first line */
         display: inline-block;
     }
-    </style>
-</head>
-<body>"#;
-
-const FOOTER: &str = r#"
-</body>
-</html>"#;
+</style>"#;
 
 /// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator.
+#[derive(Clone, Debug)]
 pub struct SpanViewable {
+    pub bb: BasicBlock,
     pub span: Span,
     pub id: String,
     pub tooltip: String,
@@ -90,14 +90,15 @@
 /// Write a spanview HTML+CSS file to analyze MIR element spans.
 pub fn write_mir_fn_spanview<'tcx, W>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
     body: &Body<'tcx>,
     spanview: MirSpanview,
+    title: &str,
     w: &mut W,
 ) -> io::Result<()>
 where
     W: Write,
 {
+    let def_id = body.source.def_id();
     let body_span = hir_body(tcx, def_id).value.span;
     let mut span_viewables = Vec::new();
     for (bb, data) in body.basic_blocks().iter_enumerated() {
@@ -126,16 +127,17 @@
             }
         }
     }
-    write_spanview_document(tcx, def_id, span_viewables, w)?;
+    write_document(tcx, def_id, span_viewables, title, w)?;
     Ok(())
 }
 
 /// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated
 /// list `SpanViewable`s.
-pub fn write_spanview_document<'tcx, W>(
+pub fn write_document<'tcx, W>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     mut span_viewables: Vec<SpanViewable>,
+    title: &str,
     w: &mut W,
 ) -> io::Result<()>
 where
@@ -153,6 +155,9 @@
         source_map.span_to_snippet(fn_span).expect("function should have printable source")
     );
     writeln!(w, "{}", HEADER)?;
+    writeln!(w, "<title>{}</title>", title)?;
+    writeln!(w, "{}", STYLE_SECTION)?;
+    writeln!(w, "{}", START_BODY)?;
     write!(
         w,
         r#"<div class="code" style="counter-reset: line {}"><span class="line">{}"#,
@@ -182,6 +187,7 @@
             end_pos.to_usize(),
             ordered_viewables.len()
         );
+        let curr_id = &ordered_viewables[0].id;
         let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps(
             tcx,
             from_pos,
@@ -204,13 +210,17 @@
         from_pos = next_from_pos;
         if next_ordered_viewables.len() != ordered_viewables.len() {
             ordered_viewables = next_ordered_viewables;
-            alt = !alt;
+            if let Some(next_ordered_viewable) = ordered_viewables.first() {
+                if &next_ordered_viewable.id != curr_id {
+                    alt = !alt;
+                }
+            }
         }
     }
     if from_pos < end_pos {
         write_coverage_gap(tcx, from_pos, end_pos, w)?;
     }
-    write!(w, r#"</span></div>"#)?;
+    writeln!(w, r#"</span></div>"#)?;
     writeln!(w, "{}", FOOTER)?;
     Ok(())
 }
@@ -273,7 +283,7 @@
     }
     let id = format!("{}[{}]", bb.index(), i);
     let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None);
-    Some(SpanViewable { span, id, tooltip })
+    Some(SpanViewable { bb, span, id, tooltip })
 }
 
 fn terminator_span_viewable<'tcx>(
@@ -289,7 +299,7 @@
     }
     let id = format!("{}:{}", bb.index(), terminator_kind_name(term));
     let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator);
-    Some(SpanViewable { span, id, tooltip })
+    Some(SpanViewable { bb, span, id, tooltip })
 }
 
 fn block_span_viewable<'tcx>(
@@ -304,7 +314,7 @@
     }
     let id = format!("{}", bb.index());
     let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator);
-    Some(SpanViewable { span, id, tooltip })
+    Some(SpanViewable { bb, span, id, tooltip })
 }
 
 fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span {
@@ -456,6 +466,7 @@
             remaining_viewables.len()
         );
         // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`.
+        let curr_id = &remaining_viewables[0].id;
         let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps(
             tcx,
             from_pos,
@@ -480,7 +491,11 @@
         from_pos = next_from_pos;
         if next_remaining_viewables.len() != remaining_viewables.len() {
             remaining_viewables = next_remaining_viewables;
-            subalt = !subalt;
+            if let Some(next_ordered_viewable) = remaining_viewables.first() {
+                if &next_ordered_viewable.id != curr_id {
+                    subalt = !subalt;
+                }
+            }
         }
     }
     if from_pos <= viewable.span.hi() {
@@ -649,8 +664,12 @@
         tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
     let fn_decl_span = tcx.hir().span(hir_id);
     let body_span = hir_body(tcx, def_id).value.span;
-    debug_assert_eq!(fn_decl_span.ctxt(), body_span.ctxt());
-    fn_decl_span.to(body_span)
+    if fn_decl_span.ctxt() == body_span.ctxt() {
+        fn_decl_span.to(body_span)
+    } else {
+        // This probably occurs for functions defined via macros
+        body_span
+    }
 }
 
 fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index beaf12b..d5f72e6 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -28,14 +28,16 @@
         self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
             this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
                 if targeted_by_break {
-                    // This is a `break`-able block
-                    let exit_block = this.cfg.start_new_block();
-                    let block_exit =
-                        this.in_breakable_scope(None, exit_block, destination, |this| {
-                            this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
-                        });
-                    this.cfg.goto(unpack!(block_exit), source_info, exit_block);
-                    exit_block.unit()
+                    this.in_breakable_scope(None, destination, span, |this| {
+                        Some(this.ast_block_stmts(
+                            destination,
+                            block,
+                            span,
+                            stmts,
+                            expr,
+                            safety_mode,
+                        ))
+                    })
                 } else {
                     this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
                 }
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 244a70f..3a36ad5 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -33,6 +33,7 @@
                 Constant { span, user_ty, literal }
             }
             ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal },
+            ExprKind::ConstBlock { value } => Constant { span, user_ty: None, literal: value },
             _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
         }
     }
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 39dbb6d..443025c 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -254,6 +254,7 @@
             | ExprKind::Continue { .. }
             | ExprKind::Return { .. }
             | ExprKind::Literal { .. }
+            | ExprKind::ConstBlock { .. }
             | ExprKind::StaticRef { .. }
             | ExprKind::InlineAsm { .. }
             | ExprKind::LlvmInlineAsm { .. }
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 9c5fddc..4033cc6 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -234,6 +234,7 @@
             }
             ExprKind::Yield { .. }
             | ExprKind::Literal { .. }
+            | ExprKind::ConstBlock { .. }
             | ExprKind::StaticRef { .. }
             | ExprKind::Block { .. }
             | ExprKind::Match { .. }
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index 9cabd18..ac5cf18 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -68,7 +68,9 @@
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
 
-            ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => Some(Category::Constant),
+            ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
+                Some(Category::Constant)
+            }
 
             ExprKind::Loop { .. }
             | ExprKind::Block { .. }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 319fae5..a268b0b 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -140,23 +140,19 @@
                 // body, even when the exact code in the body cannot unwind
 
                 let loop_block = this.cfg.start_new_block();
-                let exit_block = this.cfg.start_new_block();
 
                 // Start the loop.
                 this.cfg.goto(block, source_info, loop_block);
 
-                this.in_breakable_scope(Some(loop_block), exit_block, destination, move |this| {
+                this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
                     // conduct the test, if necessary
                     let body_block = this.cfg.start_new_block();
-                    let diverge_cleanup = this.diverge_cleanup();
                     this.cfg.terminate(
                         loop_block,
                         source_info,
-                        TerminatorKind::FalseUnwind {
-                            real_target: body_block,
-                            unwind: Some(diverge_cleanup),
-                        },
+                        TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
                     );
+                    this.diverge_from(loop_block);
 
                     // The “return” value of the loop body must always be an unit. We therefore
                     // introduce a unit temporary as the destination for the loop body.
@@ -164,8 +160,10 @@
                     // Execute the body, branching back to the test.
                     let body_block_end = unpack!(this.into(tmp, body_block, body));
                     this.cfg.goto(body_block_end, source_info, loop_block);
-                });
-                exit_block.unit()
+
+                    // Loops are only exited by `break` expressions.
+                    None
+                })
             }
             ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
                 let intrinsic = match *ty.kind() {
@@ -206,7 +204,6 @@
                         .collect();
 
                     let success = this.cfg.start_new_block();
-                    let cleanup = this.diverge_cleanup();
 
                     this.record_operands_moved(&args);
 
@@ -218,7 +215,7 @@
                         TerminatorKind::Call {
                             func: fun,
                             args,
-                            cleanup: Some(cleanup),
+                            cleanup: None,
                             // FIXME(varkor): replace this with an uninhabitedness-based check.
                             // This requires getting access to the current module to call
                             // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
@@ -231,6 +228,7 @@
                             fn_span,
                         },
                     );
+                    this.diverge_from(block);
                     success.unit()
                 }
             }
@@ -437,12 +435,12 @@
                 let scope = this.local_scope();
                 let value = unpack!(block = this.as_operand(block, scope, value));
                 let resume = this.cfg.start_new_block();
-                let cleanup = this.generator_drop_cleanup();
                 this.cfg.terminate(
                     block,
                     source_info,
-                    TerminatorKind::Yield { value, resume, resume_arg: destination, drop: cleanup },
+                    TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
                 );
+                this.generator_drop_cleanup(block);
                 resume.unit()
             }
 
@@ -456,6 +454,7 @@
             | ExprKind::Array { .. }
             | ExprKind::Tuple { .. }
             | ExprKind::Closure { .. }
+            | ExprKind::ConstBlock { .. }
             | ExprKind::Literal { .. }
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::StaticRef { .. } => {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index a9b8a61..b7bd67f 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -228,8 +228,6 @@
         outer_source_info: SourceInfo,
         fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
     ) -> BlockAnd<()> {
-        let match_scope = self.scopes.topmost();
-
         let arm_end_blocks: Vec<_> = arm_candidates
             .into_iter()
             .map(|(arm, candidate)| {
@@ -250,7 +248,7 @@
                     let arm_block = this.bind_pattern(
                         outer_source_info,
                         candidate,
-                        arm.guard.as_ref().map(|g| (g, match_scope)),
+                        arm.guard.as_ref(),
                         &fake_borrow_temps,
                         scrutinee_span,
                         Some(arm.scope),
@@ -287,7 +285,7 @@
         &mut self,
         outer_source_info: SourceInfo,
         candidate: Candidate<'_, 'tcx>,
-        guard: Option<(&Guard<'tcx>, region::Scope)>,
+        guard: Option<&Guard<'tcx>>,
         fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
         scrutinee_span: Span,
         arm_scope: Option<region::Scope>,
@@ -1592,7 +1590,7 @@
         &mut self,
         candidate: Candidate<'pat, 'tcx>,
         parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
-        guard: Option<(&Guard<'tcx>, region::Scope)>,
+        guard: Option<&Guard<'tcx>>,
         fake_borrows: &Vec<(Place<'tcx>, Local)>,
         scrutinee_span: Span,
         schedule_drops: bool,
@@ -1704,7 +1702,7 @@
         //      the reference that we create for the arm.
         //    * So we eagerly create the reference for the arm and then take a
         //      reference to that.
-        if let Some((guard, region_scope)) = guard {
+        if let Some(guard) = guard {
             let tcx = self.hir.tcx();
             let bindings = parent_bindings
                 .iter()
@@ -1748,12 +1746,7 @@
                 unreachable
             });
             let outside_scope = self.cfg.start_new_block();
-            self.exit_scope(
-                source_info.span,
-                region_scope,
-                otherwise_post_guard_block,
-                outside_scope,
-            );
+            self.exit_top_scope(otherwise_post_guard_block, outside_scope, source_info);
             self.false_edges(
                 outside_scope,
                 otherwise_block,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index a28a181..e462747 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -28,8 +28,9 @@
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Simplify a candidate so that all match pairs require a test.
     ///
-    /// This method will also split a candidate where the only match-pair is an
-    /// or-pattern into multiple candidates. This is so that
+    /// This method will also split a candidate, in which the only
+    /// match-pair is an or-pattern, into multiple candidates.
+    /// This is so that
     ///
     /// match x {
     ///     0 | 1 => { ... },
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index d81c3b6..c419190 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -167,48 +167,42 @@
                 let target_blocks = make_target_blocks(self);
                 // Variants is a BitVec of indexes into adt_def.variants.
                 let num_enum_variants = adt_def.variants.len();
-                let used_variants = variants.count();
                 debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
                 let otherwise_block = *target_blocks.last().unwrap();
-                let mut targets = Vec::with_capacity(used_variants + 1);
-                let mut values = Vec::with_capacity(used_variants);
                 let tcx = self.hir.tcx();
-                for (idx, discr) in adt_def.discriminants(tcx) {
-                    if variants.contains(idx) {
-                        debug_assert_ne!(
-                            target_blocks[idx.index()],
-                            otherwise_block,
-                            "no canididates for tested discriminant: {:?}",
-                            discr,
-                        );
-                        values.push(discr.val);
-                        targets.push(target_blocks[idx.index()]);
-                    } else {
-                        debug_assert_eq!(
-                            target_blocks[idx.index()],
-                            otherwise_block,
-                            "found canididates for untested discriminant: {:?}",
-                            discr,
-                        );
-                    }
-                }
-                targets.push(otherwise_block);
-                debug!(
-                    "num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
-                    num_enum_variants, values, variants
+                let switch_targets = SwitchTargets::new(
+                    adt_def.discriminants(tcx).filter_map(|(idx, discr)| {
+                        if variants.contains(idx) {
+                            debug_assert_ne!(
+                                target_blocks[idx.index()],
+                                otherwise_block,
+                                "no canididates for tested discriminant: {:?}",
+                                discr,
+                            );
+                            Some((discr.val, target_blocks[idx.index()]))
+                        } else {
+                            debug_assert_eq!(
+                                target_blocks[idx.index()],
+                                otherwise_block,
+                                "found canididates for untested discriminant: {:?}",
+                                discr,
+                            );
+                            None
+                        }
+                    }),
+                    otherwise_block,
                 );
+                debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants);
                 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
                 let discr = self.temp(discr_ty, test.span);
                 self.cfg.push_assign(block, source_info, discr, Rvalue::Discriminant(place));
-                assert_eq!(values.len() + 1, targets.len());
                 self.cfg.terminate(
                     block,
                     source_info,
                     TerminatorKind::SwitchInt {
                         discr: Operand::Move(discr),
                         switch_ty: discr_ty,
-                        values: From::from(values),
-                        targets,
+                        targets: switch_targets,
                     },
                 );
             }
@@ -230,11 +224,15 @@
                 } else {
                     // The switch may be inexhaustive so we have a catch all block
                     debug_assert_eq!(options.len() + 1, target_blocks.len());
+                    let otherwise_block = *target_blocks.last().unwrap();
+                    let switch_targets = SwitchTargets::new(
+                        options.values().copied().zip(target_blocks),
+                        otherwise_block,
+                    );
                     TerminatorKind::SwitchInt {
                         discr: Operand::Copy(place),
                         switch_ty,
-                        values: options.values().copied().collect(),
-                        targets: target_blocks,
+                        targets: switch_targets,
                     }
                 };
                 self.cfg.terminate(block, source_info, terminator);
@@ -418,7 +416,6 @@
         let bool_ty = self.hir.bool_ty();
         let eq_result = self.temp(bool_ty, source_info.span);
         let eq_block = self.cfg.start_new_block();
-        let cleanup = self.diverge_cleanup();
         self.cfg.terminate(
             block,
             source_info,
@@ -436,11 +433,12 @@
                 }),
                 args: vec![val, expect],
                 destination: Some((eq_result, eq_block)),
-                cleanup: Some(cleanup),
+                cleanup: None,
                 from_hir_call: false,
                 fn_span: source_info.span,
             },
         );
+        self.diverge_from(block);
 
         if let [success_block, fail_block] = *make_target_blocks(self) {
             // check the result
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index aa96ae8..899fc64 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -29,7 +29,13 @@
         return tcx.mir_built(def);
     }
 
-    tcx.alloc_steal_mir(mir_build(tcx, def))
+    let mut body = mir_build(tcx, def);
+    if def.const_param_did.is_some() {
+        assert!(matches!(body.source.instance, ty::InstanceDef::Item(_)));
+        body.source = MirSource::from_instance(ty::InstanceDef::Item(def.to_global()));
+    }
+
+    tcx.alloc_steal_mir(body)
 }
 
 /// Construct the MIR for a given `DefId`.
@@ -199,7 +205,7 @@
             build::construct_const(cx, body_id, return_ty, return_ty_span)
         };
 
-        lints::check(tcx, &body, def.did);
+        lints::check(tcx, &body);
 
         // The borrow checker will replace all the regions here with its own
         // inference variables. There's no point having non-erased regions here.
@@ -296,6 +302,7 @@
     hir: Cx<'a, 'tcx>,
     cfg: CFG<'tcx>,
 
+    def_id: DefId,
     fn_span: Span,
     arg_count: usize,
     generator_kind: Option<GeneratorKind>,
@@ -344,14 +351,6 @@
     unit_temp: Option<Place<'tcx>>,
 
     var_debug_info: Vec<VarDebugInfo<'tcx>>,
-
-    /// Cached block with the `RESUME` terminator; this is created
-    /// when first set of cleanups are built.
-    cached_resume_block: Option<BasicBlock>,
-    /// Cached block with the `RETURN` terminator.
-    cached_return_block: Option<BasicBlock>,
-    /// Cached block with the `UNREACHABLE` terminator.
-    cached_unreachable_block: Option<BasicBlock>,
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -597,6 +596,7 @@
 
     let mut builder = Builder::new(
         hir,
+        fn_def_id.to_def_id(),
         span_with_body,
         arguments.len(),
         safety,
@@ -609,50 +609,30 @@
         region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite };
     let arg_scope =
         region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Arguments };
-    let mut block = START_BLOCK;
     let source_info = builder.source_info(span);
     let call_site_s = (call_site_scope, source_info);
-    unpack!(
-        block = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
-            if should_abort_on_panic(tcx, fn_def_id, abi) {
-                builder.schedule_abort();
-            }
-
-            let arg_scope_s = (arg_scope, source_info);
-            // `return_block` is called when we evaluate a `return` expression, so
-            // we just use `START_BLOCK` here.
-            unpack!(
-                block = builder.in_breakable_scope(
-                    None,
-                    START_BLOCK,
-                    Place::return_place(),
-                    |builder| {
-                        builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
-                            builder.args_and_body(
-                                block,
-                                fn_def_id.to_def_id(),
-                                &arguments,
-                                arg_scope,
-                                &body.value,
-                            )
-                        })
-                    },
-                )
-            );
-            // Attribute epilogue to function's closing brace
-            let fn_end = span_with_body.shrink_to_hi();
-            let source_info = builder.source_info(fn_end);
-            let return_block = builder.return_block();
-            builder.cfg.goto(block, source_info, return_block);
-            builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
-            // Attribute any unreachable codepaths to the function's closing brace
-            if let Some(unreachable_block) = builder.cached_unreachable_block {
-                builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable);
-            }
-            return_block.unit()
-        })
-    );
-    assert_eq!(block, builder.return_block());
+    unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
+        let arg_scope_s = (arg_scope, source_info);
+        // Attribute epilogue to function's closing brace
+        let fn_end = span_with_body.shrink_to_hi();
+        let return_block =
+            unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
+                Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
+                    builder.args_and_body(
+                        START_BLOCK,
+                        fn_def_id.to_def_id(),
+                        &arguments,
+                        arg_scope,
+                        &body.value,
+                    )
+                }))
+            }));
+        let source_info = builder.source_info(fn_end);
+        builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
+        let should_abort = should_abort_on_panic(tcx, fn_def_id, abi);
+        builder.build_drop_trees(should_abort);
+        return_block.unit()
+    }));
 
     let spread_arg = if abi == Abi::RustCall {
         // RustCall pseudo-ABI untuples the last argument.
@@ -675,8 +655,9 @@
 ) -> Body<'tcx> {
     let tcx = hir.tcx();
     let owner_id = tcx.hir().body_owner(body_id);
+    let def_id = tcx.hir().local_def_id(owner_id);
     let span = tcx.hir().span(owner_id);
-    let mut builder = Builder::new(hir, span, 0, Safety::Safe, const_ty, const_ty_span, None);
+    let mut builder = Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None);
 
     let mut block = START_BLOCK;
     let ast_expr = &tcx.hir().body(body_id).value;
@@ -686,14 +667,7 @@
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
 
-    // Constants can't `return` so a return block should not be created.
-    assert_eq!(builder.cached_return_block, None);
-
-    // Constants may be match expressions in which case an unreachable block may
-    // be created, so terminate it properly.
-    if let Some(unreachable_block) = builder.cached_unreachable_block {
-        builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable);
-    }
+    builder.build_drop_trees(false);
 
     builder.finish()
 }
@@ -705,6 +679,7 @@
 fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> {
     let tcx = hir.tcx();
     let owner_id = tcx.hir().body_owner(body_id);
+    let def_id = tcx.hir().local_def_id(owner_id);
     let span = tcx.hir().span(owner_id);
     let ty = tcx.ty_error();
     let num_params = match hir.body_owner_kind {
@@ -722,7 +697,7 @@
         hir::BodyOwnerKind::Const => 0,
         hir::BodyOwnerKind::Static(_) => 0,
     };
-    let mut builder = Builder::new(hir, span, num_params, Safety::Safe, ty, span, None);
+    let mut builder = Builder::new(hir, def_id.to_def_id(), span, num_params, Safety::Safe, ty, span, None);
     let source_info = builder.source_info(span);
     // Some MIR passes will expect the number of parameters to match the
     // function declaration.
@@ -740,6 +715,7 @@
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn new(
         hir: Cx<'a, 'tcx>,
+        def_id: DefId,
         span: Span,
         arg_count: usize,
         safety: Safety,
@@ -750,11 +726,12 @@
         let lint_level = LintLevel::Explicit(hir.root_lint_level);
         let mut builder = Builder {
             hir,
+            def_id,
             cfg: CFG { basic_blocks: IndexVec::new() },
             fn_span: span,
             arg_count,
             generator_kind,
-            scopes: Default::default(),
+            scopes: scope::Scopes::new(),
             block_context: BlockContext::new(),
             source_scopes: IndexVec::new(),
             source_scope: OUTERMOST_SOURCE_SCOPE,
@@ -767,9 +744,6 @@
             var_indices: Default::default(),
             unit_temp: None,
             var_debug_info: vec![],
-            cached_resume_block: None,
-            cached_return_block: None,
-            cached_unreachable_block: None,
         };
 
         assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
@@ -790,6 +764,7 @@
         }
 
         Body::new(
+            MirSource::item(self.def_id),
             self.cfg.basic_blocks,
             self.source_scopes,
             self.local_decls,
@@ -1003,17 +978,6 @@
             }
         }
     }
-
-    fn return_block(&mut self) -> BasicBlock {
-        match self.cached_return_block {
-            Some(rb) => rb,
-            None => {
-                let rb = self.cfg.start_new_block();
-                self.cached_return_block = Some(rb);
-                rb
-            }
-        }
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 2a03bb7..ad6386c 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -6,30 +6,31 @@
 
 ### SEME Regions
 
-When pushing a new scope, we record the current point in the graph (a
+When pushing a new [Scope], we record the current point in the graph (a
 basic block); this marks the entry to the scope. We then generate more
 stuff in the control-flow graph. Whenever the scope is exited, either
 via a `break` or `return` or just by fallthrough, that marks an exit
 from the scope. Each lexical scope thus corresponds to a single-entry,
 multiple-exit (SEME) region in the control-flow graph.
 
-For now, we keep a mapping from each `region::Scope` to its
-corresponding SEME region for later reference (see caveat in next
-paragraph). This is because region scopes are tied to
-them. Eventually, when we shift to non-lexical lifetimes, there should
-be no need to remember this mapping.
+For now, we record the `region::Scope` to each SEME region for later reference
+(see caveat in next paragraph). This is because destruction scopes are tied to
+them. This may change in the future so that MIR lowering determines its own
+destruction scopes.
 
 ### Not so SEME Regions
 
 In the course of building matches, it sometimes happens that certain code
 (namely guards) gets executed multiple times. This means that the scope lexical
 scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
-mapping is from one scope to a vector of SEME regions.
+mapping is from one scope to a vector of SEME regions. Since the SEME regions
+are disjoint, the mapping is still one-to-one for the set of SEME regions that
+we're currently in.
 
-Also in matches, the scopes assigned to arms are not even SEME regions! Each
-arm has a single region with one entry for each pattern. We manually
+Also in matches, the scopes assigned to arms are not always even SEME regions!
+Each arm has a single region with one entry for each pattern. We manually
 manipulate the scheduled drops in this scope to avoid dropping things multiple
-times, although drop elaboration would clean this up for value drops.
+times.
 
 ### Drops
 
@@ -60,25 +61,23 @@
 
 There are numerous "normal" ways to early exit a scope: `break`,
 `continue`, `return` (panics are handled separately). Whenever an
-early exit occurs, the method `exit_scope` is called. It is given the
+early exit occurs, the method `break_scope` is called. It is given the
 current point in execution where the early exit occurs, as well as the
 scope you want to branch to (note that all early exits from to some
-other enclosing scope). `exit_scope` will record this exit point and
-also add all drops.
+other enclosing scope). `break_scope` will record the set of drops currently
+scheduled in a [DropTree]. Later, before `in_breakable_scope` exits, the drops
+will be added to the CFG.
 
-Panics are handled in a similar fashion, except that a panic always
-returns out to the `DIVERGE_BLOCK`. To trigger a panic, simply call
-`panic(p)` with the current point `p`. Or else you can call
-`diverge_cleanup`, which will produce a block that you can branch to
-which does the appropriate cleanup and then diverges. `panic(p)`
-simply calls `diverge_cleanup()` and adds an edge from `p` to the
-result.
+Panics are handled in a similar fashion, except that the drops are added to the
+MIR once the rest of the function has finished being lowered. If a terminator
+can panic, call `diverge_from(block)` with the block containing the terminator
+`block`.
 
-### Loop scopes
+### Breakable scopes
 
 In addition to the normal scope stack, we track a loop scope stack
-that contains only loops. It tracks where a `break` and `continue`
-should go to.
+that contains only loops and breakable blocks. It tracks where a `break`,
+`continue` or `return` should go to.
 
 */
 
@@ -86,12 +85,24 @@
 use crate::thir::{Expr, ExprRef, LintLevel};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::GeneratorKind;
+use rustc_index::vec::IndexVec;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_span::{Span, DUMMY_SP};
-use std::collections::hash_map::Entry;
-use std::mem;
+
+#[derive(Debug)]
+pub struct Scopes<'tcx> {
+    scopes: Vec<Scope>,
+    /// The current set of breakable scopes. See module comment for more details.
+    breakable_scopes: Vec<BreakableScope<'tcx>>,
+
+    /// Drops that need to be done on unwind paths. See the comment on
+    /// [DropTree] for more details.
+    unwind_drops: DropTree,
+
+    /// Drops that need to be done on paths to the `GeneratorDrop` terminator.
+    generator_drops: DropTree,
+}
 
 #[derive(Debug)]
 struct Scope {
@@ -112,73 +123,45 @@
 
     moved_locals: Vec<Local>,
 
-    /// The cache for drop chain on “normal” exit into a particular BasicBlock.
-    cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>,
+    /// The drop index that will drop everything in and below this scope on an
+    /// unwind path.
+    cached_unwind_block: Option<DropIdx>,
 
-    /// The cache for drop chain on "generator drop" exit.
-    cached_generator_drop: Option<BasicBlock>,
-
-    /// The cache for drop chain on "unwind" exit.
-    cached_unwind: CachedBlock,
+    /// The drop index that will drop everything in and below this scope on a
+    /// generator drop path.
+    cached_generator_drop_block: Option<DropIdx>,
 }
 
-#[derive(Debug, Default)]
-crate struct Scopes<'tcx> {
-    scopes: Vec<Scope>,
-    /// The current set of breakable scopes. See module comment for more details.
-    breakable_scopes: Vec<BreakableScope<'tcx>>,
-}
-
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
 struct DropData {
-    /// span where drop obligation was incurred (typically where place was declared)
-    span: Span,
+    /// The `Span` where drop obligation was incurred (typically where place was
+    /// declared)
+    source_info: SourceInfo,
 
     /// local to drop
     local: Local,
 
     /// Whether this is a value Drop or a StorageDead.
     kind: DropKind,
-
-    /// The cached blocks for unwinds.
-    cached_block: CachedBlock,
 }
 
-#[derive(Debug, Default, Clone, Copy)]
-struct CachedBlock {
-    /// The cached block for the cleanups-on-diverge path. This block
-    /// contains code to run the current drop and all the preceding
-    /// drops (i.e., those having lower index in Drop’s Scope drop
-    /// array)
-    unwind: Option<BasicBlock>,
-
-    /// The cached block for unwinds during cleanups-on-generator-drop path
-    ///
-    /// This is split from the standard unwind path here to prevent drop
-    /// elaboration from creating drop flags that would have to be captured
-    /// by the generator. I'm not sure how important this optimization is,
-    /// but it is here.
-    generator_drop: Option<BasicBlock>,
-}
-
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub(crate) enum DropKind {
     Value,
     Storage,
 }
 
-#[derive(Clone, Debug)]
+#[derive(Debug)]
 struct BreakableScope<'tcx> {
     /// Region scope of the loop
     region_scope: region::Scope,
-    /// Where the body of the loop begins. `None` if block
-    continue_block: Option<BasicBlock>,
-    /// Block to branch into when the loop or block terminates (either by being
-    /// `break`-en out from, or by having its condition to become false)
-    break_block: BasicBlock,
     /// The destination of the loop/block expression itself (i.e., where to put
-    /// the result of a `break` expression)
+    /// the result of a `break` or `return` expression)
     break_destination: Place<'tcx>,
+    /// Drops that happen on the `break`/`return` path.
+    break_drops: DropTree,
+    /// Drops that happen on the `continue` path.
+    continue_drops: Option<DropTree>,
 }
 
 /// The target of an expression that breaks out of a scope
@@ -189,61 +172,33 @@
     Return,
 }
 
-impl CachedBlock {
-    fn invalidate(&mut self) {
-        *self = CachedBlock::default();
-    }
+rustc_index::newtype_index! {
+    struct DropIdx { .. }
+}
 
-    fn get(&self, generator_drop: bool) -> Option<BasicBlock> {
-        if generator_drop { self.generator_drop } else { self.unwind }
-    }
+const ROOT_NODE: DropIdx = DropIdx::from_u32(0);
 
-    fn ref_mut(&mut self, generator_drop: bool) -> &mut Option<BasicBlock> {
-        if generator_drop { &mut self.generator_drop } else { &mut self.unwind }
-    }
+/// A tree of drops that we have deferred lowering. It's used for:
+///
+/// * Drops on unwind paths
+/// * Drops on generator drop paths (when a suspended generator is dropped)
+/// * Drops on return and loop exit paths
+///
+/// Once no more nodes could be added to the tree, we lower it to MIR in one go
+/// in `build_mir`.
+#[derive(Debug)]
+struct DropTree {
+    /// Drops in the tree.
+    drops: IndexVec<DropIdx, (DropData, DropIdx)>,
+    /// Map for finding the inverse of the `next_drop` relation:
+    ///
+    /// `previous_drops[(drops[i].1, drops[i].0.local, drops[i].0.kind)] == i`
+    previous_drops: FxHashMap<(DropIdx, Local, DropKind), DropIdx>,
+    /// Edges into the `DropTree` that need to be added once it's lowered.
+    entry_points: Vec<(DropIdx, BasicBlock)>,
 }
 
 impl Scope {
-    /// Invalidates all the cached blocks in the scope.
-    ///
-    /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
-    /// larger extent of code.
-    ///
-    /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`.
-    /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
-    /// top-of-scope (as opposed to dependent scopes).
-    fn invalidate_cache(
-        &mut self,
-        storage_only: bool,
-        generator_kind: Option<GeneratorKind>,
-        this_scope_only: bool,
-    ) {
-        // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
-        // with lots of `try!`?
-
-        // cached exits drop storage and refer to the top-of-scope
-        self.cached_exits.clear();
-
-        // the current generator drop and unwind refer to top-of-scope
-        self.cached_generator_drop = None;
-
-        let ignore_unwinds = storage_only && generator_kind.is_none();
-        if !ignore_unwinds {
-            self.cached_unwind.invalidate();
-        }
-
-        if !ignore_unwinds && !this_scope_only {
-            for drop_data in &mut self.drops {
-                drop_data.cached_block.invalidate();
-            }
-        }
-    }
-
-    /// Given a span and this scope's source scope, make a SourceInfo.
-    fn source_info(&self, span: Span) -> SourceInfo {
-        SourceInfo { span, scope: self.source_scope }
-    }
-
     /// Whether there's anything to do for the cleanup path, that is,
     /// when unwinding through this scope. This includes destructors,
     /// but not StorageDead statements, which don't get emitted at all
@@ -261,11 +216,189 @@
             DropKind::Storage => false,
         })
     }
+
+    fn invalidate_cache(&mut self) {
+        self.cached_unwind_block = None;
+        self.cached_generator_drop_block = None;
+    }
+}
+
+/// A trait that determined how [DropTree] creates its blocks and
+/// links to any entry nodes.
+trait DropTreeBuilder<'tcx> {
+    /// Create a new block for the tree. This should call either
+    /// `cfg.start_new_block()` or `cfg.start_new_cleanup_block()`.
+    fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock;
+
+    /// Links a block outside the drop tree, `from`, to the block `to` inside
+    /// the drop tree.
+    fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock);
+}
+
+impl DropTree {
+    fn new() -> Self {
+        // The root node of the tree doesn't represent a drop, but instead
+        // represents the block in the tree that should be jumped to once all
+        // of the required drops have been performed.
+        let fake_source_info = SourceInfo::outermost(DUMMY_SP);
+        let fake_data =
+            DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
+        let drop_idx = DropIdx::MAX;
+        let drops = IndexVec::from_elem_n((fake_data, drop_idx), 1);
+        Self { drops, entry_points: Vec::new(), previous_drops: FxHashMap::default() }
+    }
+
+    fn add_drop(&mut self, drop: DropData, next: DropIdx) -> DropIdx {
+        let drops = &mut self.drops;
+        *self
+            .previous_drops
+            .entry((next, drop.local, drop.kind))
+            .or_insert_with(|| drops.push((drop, next)))
+    }
+
+    fn add_entry(&mut self, from: BasicBlock, to: DropIdx) {
+        debug_assert!(to < self.drops.next_index());
+        self.entry_points.push((to, from));
+    }
+
+    /// Builds the MIR for a given drop tree.
+    ///
+    /// `blocks` should have the same length as `self.drops`, and may have its
+    /// first value set to some already existing block.
+    fn build_mir<'tcx, T: DropTreeBuilder<'tcx>>(
+        &mut self,
+        cfg: &mut CFG<'tcx>,
+        blocks: &mut IndexVec<DropIdx, Option<BasicBlock>>,
+    ) {
+        debug!("DropTree::build_mir(drops = {:#?})", self);
+        assert_eq!(blocks.len(), self.drops.len());
+
+        self.assign_blocks::<T>(cfg, blocks);
+        self.link_blocks(cfg, blocks)
+    }
+
+    /// Assign blocks for all of the drops in the drop tree that need them.
+    fn assign_blocks<'tcx, T: DropTreeBuilder<'tcx>>(
+        &mut self,
+        cfg: &mut CFG<'tcx>,
+        blocks: &mut IndexVec<DropIdx, Option<BasicBlock>>,
+    ) {
+        // StorageDead statements can share blocks with each other and also with
+        // a Drop terminator. We iterate through the drops to find which drops
+        // need their own block.
+        #[derive(Clone, Copy)]
+        enum Block {
+            // This drop is unreachable
+            None,
+            // This drop is only reachable through the `StorageDead` with the
+            // specified index.
+            Shares(DropIdx),
+            // This drop has more than one way of being reached, or it is
+            // branched to from outside the tree, or its predecessor is a
+            // `Value` drop.
+            Own,
+        }
+
+        let mut needs_block = IndexVec::from_elem(Block::None, &self.drops);
+        if blocks[ROOT_NODE].is_some() {
+            // In some cases (such as drops for `continue`) the root node
+            // already has a block. In this case, make sure that we don't
+            // override it.
+            needs_block[ROOT_NODE] = Block::Own;
+        }
+
+        // Sort so that we only need to check the last value.
+        let entry_points = &mut self.entry_points;
+        entry_points.sort();
+
+        for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
+            if entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
+                let block = *blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
+                needs_block[drop_idx] = Block::Own;
+                while entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
+                    let entry_block = entry_points.pop().unwrap().1;
+                    T::add_entry(cfg, entry_block, block);
+                }
+            }
+            match needs_block[drop_idx] {
+                Block::None => continue,
+                Block::Own => {
+                    blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
+                }
+                Block::Shares(pred) => {
+                    blocks[drop_idx] = blocks[pred];
+                }
+            }
+            if let DropKind::Value = drop_data.0.kind {
+                needs_block[drop_data.1] = Block::Own;
+            } else {
+                if drop_idx != ROOT_NODE {
+                    match &mut needs_block[drop_data.1] {
+                        pred @ Block::None => *pred = Block::Shares(drop_idx),
+                        pred @ Block::Shares(_) => *pred = Block::Own,
+                        Block::Own => (),
+                    }
+                }
+            }
+        }
+
+        debug!("assign_blocks: blocks = {:#?}", blocks);
+        assert!(entry_points.is_empty());
+    }
+
+    fn link_blocks<'tcx>(
+        &self,
+        cfg: &mut CFG<'tcx>,
+        blocks: &IndexVec<DropIdx, Option<BasicBlock>>,
+    ) {
+        for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
+            let block = if let Some(block) = blocks[drop_idx] {
+                block
+            } else {
+                continue;
+            };
+            match drop_data.0.kind {
+                DropKind::Value => {
+                    let terminator = TerminatorKind::Drop {
+                        target: blocks[drop_data.1].unwrap(),
+                        // The caller will handle this if needed.
+                        unwind: None,
+                        place: drop_data.0.local.into(),
+                    };
+                    cfg.terminate(block, drop_data.0.source_info, terminator);
+                }
+                // Root nodes don't correspond to a drop.
+                DropKind::Storage if drop_idx == ROOT_NODE => {}
+                DropKind::Storage => {
+                    let stmt = Statement {
+                        source_info: drop_data.0.source_info,
+                        kind: StatementKind::StorageDead(drop_data.0.local),
+                    };
+                    cfg.push(block, stmt);
+                    let target = blocks[drop_data.1].unwrap();
+                    if target != block {
+                        // Diagnostics don't use this `Span` but debuginfo
+                        // might. Since we don't want breakpoints to be placed
+                        // here, especially when this is on an unwind path, we
+                        // use `DUMMY_SP`.
+                        let source_info = SourceInfo { span: DUMMY_SP, ..drop_data.0.source_info };
+                        let terminator = TerminatorKind::Goto { target };
+                        cfg.terminate(block, source_info, terminator);
+                    }
+                }
+            }
+        }
+    }
 }
 
 impl<'tcx> Scopes<'tcx> {
-    fn len(&self) -> usize {
-        self.scopes.len()
+    pub(crate) fn new() -> Self {
+        Self {
+            scopes: Vec::new(),
+            breakable_scopes: Vec::new(),
+            unwind_drops: DropTree::new(),
+            generator_drops: DropTree::new(),
+        }
     }
 
     fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) {
@@ -276,94 +409,29 @@
             region_scope_span: region_scope.1.span,
             drops: vec![],
             moved_locals: vec![],
-            cached_generator_drop: None,
-            cached_exits: Default::default(),
-            cached_unwind: CachedBlock::default(),
+            cached_unwind_block: None,
+            cached_generator_drop_block: None,
         });
     }
 
-    fn pop_scope(
-        &mut self,
-        region_scope: (region::Scope, SourceInfo),
-    ) -> (Scope, Option<BasicBlock>) {
+    fn pop_scope(&mut self, region_scope: (region::Scope, SourceInfo)) -> Scope {
         let scope = self.scopes.pop().unwrap();
         assert_eq!(scope.region_scope, region_scope.0);
-        let unwind_to =
-            self.scopes.last().and_then(|next_scope| next_scope.cached_unwind.get(false));
-        (scope, unwind_to)
+        scope
     }
 
-    fn may_panic(&self, scope_count: usize) -> bool {
-        let len = self.len();
-        self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup())
-    }
-
-    /// Finds the breakable scope for a given label. This is used for
-    /// resolving `return`, `break` and `continue`.
-    fn find_breakable_scope(
-        &self,
-        span: Span,
-        target: BreakableTarget,
-    ) -> (BasicBlock, region::Scope, Option<Place<'tcx>>) {
-        let get_scope = |scope: region::Scope| {
-            // find the loop-scope by its `region::Scope`.
-            self.breakable_scopes
-                .iter()
-                .rfind(|breakable_scope| breakable_scope.region_scope == scope)
-                .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
-        };
-        match target {
-            BreakableTarget::Return => {
-                let scope = &self.breakable_scopes[0];
-                if scope.break_destination != Place::return_place() {
-                    span_bug!(span, "`return` in item with no return scope");
-                }
-                (scope.break_block, scope.region_scope, Some(scope.break_destination))
-            }
-            BreakableTarget::Break(scope) => {
-                let scope = get_scope(scope);
-                (scope.break_block, scope.region_scope, Some(scope.break_destination))
-            }
-            BreakableTarget::Continue(scope) => {
-                let scope = get_scope(scope);
-                let continue_block = scope
-                    .continue_block
-                    .unwrap_or_else(|| span_bug!(span, "missing `continue` block"));
-                (continue_block, scope.region_scope, None)
-            }
-        }
-    }
-
-    fn num_scopes_above(&self, region_scope: region::Scope, span: Span) -> usize {
-        let scope_count = self
-            .scopes
+    fn scope_index(&self, region_scope: region::Scope, span: Span) -> usize {
+        self.scopes
             .iter()
-            .rev()
-            .position(|scope| scope.region_scope == region_scope)
-            .unwrap_or_else(|| span_bug!(span, "region_scope {:?} does not enclose", region_scope));
-        let len = self.len();
-        assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
-        scope_count
-    }
-
-    fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
-        self.scopes.iter_mut().rev()
-    }
-
-    fn top_scopes(&mut self, count: usize) -> impl DoubleEndedIterator<Item = &mut Scope> + '_ {
-        let len = self.len();
-        self.scopes[len - count..].iter_mut()
+            .rposition(|scope| scope.region_scope == region_scope)
+            .unwrap_or_else(|| span_bug!(span, "region_scope {:?} does not enclose", region_scope))
     }
 
     /// Returns the topmost active scope, which is known to be alive until
     /// the next scope expression.
-    pub(super) fn topmost(&self) -> region::Scope {
+    fn topmost(&self) -> region::Scope {
         self.scopes.last().expect("topmost_scope: no scopes present").region_scope
     }
-
-    fn source_info(&self, index: usize, span: Span) -> SourceInfo {
-        self.scopes[self.len() - index].source_info(span)
-    }
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -371,28 +439,50 @@
     // ==========================
     //  Start a breakable scope, which tracks where `continue`, `break` and
     //  `return` should branch to.
-    crate fn in_breakable_scope<F, R>(
+    crate fn in_breakable_scope<F>(
         &mut self,
         loop_block: Option<BasicBlock>,
-        break_block: BasicBlock,
         break_destination: Place<'tcx>,
+        span: Span,
         f: F,
-    ) -> R
+    ) -> BlockAnd<()>
     where
-        F: FnOnce(&mut Builder<'a, 'tcx>) -> R,
+        F: FnOnce(&mut Builder<'a, 'tcx>) -> Option<BlockAnd<()>>,
     {
         let region_scope = self.scopes.topmost();
         let scope = BreakableScope {
             region_scope,
-            continue_block: loop_block,
-            break_block,
             break_destination,
+            break_drops: DropTree::new(),
+            continue_drops: loop_block.map(|_| DropTree::new()),
         };
         self.scopes.breakable_scopes.push(scope);
-        let res = f(self);
+        let normal_exit_block = f(self);
         let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
         assert!(breakable_scope.region_scope == region_scope);
-        res
+        let break_block = self.build_exit_tree(breakable_scope.break_drops, None);
+        breakable_scope.continue_drops.map(|drops| {
+            self.build_exit_tree(drops, loop_block);
+        });
+        match (normal_exit_block, break_block) {
+            (Some(block), None) | (None, Some(block)) => block,
+            (None, None) => self.cfg.start_new_block().unit(),
+            (Some(normal_block), Some(exit_block)) => {
+                let target = self.cfg.start_new_block();
+                let source_info = self.source_info(span);
+                self.cfg.terminate(
+                    unpack!(normal_block),
+                    source_info,
+                    TerminatorKind::Goto { target },
+                );
+                self.cfg.terminate(
+                    unpack!(exit_block),
+                    source_info,
+                    TerminatorKind::Goto { target },
+                );
+                target.unit()
+            }
+        }
     }
 
     crate fn in_opt_scope<F, R>(
@@ -476,46 +566,51 @@
         mut block: BasicBlock,
     ) -> BlockAnd<()> {
         debug!("pop_scope({:?}, {:?})", region_scope, block);
-        // If we are emitting a `drop` statement, we need to have the cached
-        // diverge cleanup pads ready in case that drop panics.
-        if self.scopes.may_panic(1) {
-            self.diverge_cleanup();
-        }
-        let (scope, unwind_to) = self.scopes.pop_scope(region_scope);
-        let unwind_to = unwind_to.unwrap_or_else(|| self.resume_block());
 
-        unpack!(
-            block = build_scope_drops(
-                &mut self.cfg,
-                self.generator_kind,
-                &scope,
-                block,
-                unwind_to,
-                self.arg_count,
-                false, // not generator
-                false, // not unwind path
-            )
-        );
+        block = self.leave_top_scope(block);
+
+        self.scopes.pop_scope(region_scope);
 
         block.unit()
     }
 
+    /// Sets up the drops for breaking from `block` to `target`.
     crate fn break_scope(
         &mut self,
         mut block: BasicBlock,
         value: Option<ExprRef<'tcx>>,
-        scope: BreakableTarget,
+        target: BreakableTarget,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
-        let (mut target_block, region_scope, destination) =
-            self.scopes.find_breakable_scope(source_info.span, scope);
-        if let BreakableTarget::Return = scope {
-            // We call this now, rather than when we start lowering the
-            // function so that the return block doesn't precede the entire
-            // rest of the CFG. Some passes and LLVM prefer blocks to be in
-            // approximately CFG order.
-            target_block = self.return_block();
-        }
+        let span = source_info.span;
+
+        let get_scope_index = |scope: region::Scope| {
+            // find the loop-scope by its `region::Scope`.
+            self.scopes
+                .breakable_scopes
+                .iter()
+                .rposition(|breakable_scope| breakable_scope.region_scope == scope)
+                .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
+        };
+        let (break_index, destination) = match target {
+            BreakableTarget::Return => {
+                let scope = &self.scopes.breakable_scopes[0];
+                if scope.break_destination != Place::return_place() {
+                    span_bug!(span, "`return` in item with no return scope");
+                }
+                (0, Some(scope.break_destination))
+            }
+            BreakableTarget::Break(scope) => {
+                let break_index = get_scope_index(scope);
+                let scope = &self.scopes.breakable_scopes[break_index];
+                (break_index, Some(scope.break_destination))
+            }
+            BreakableTarget::Continue(scope) => {
+                let break_index = get_scope_index(scope);
+                (break_index, None)
+            }
+        };
+
         if let Some(destination) = destination {
             if let Some(value) = value {
                 debug!("stmt_expr Break val block_context.push(SubExpr)");
@@ -528,131 +623,57 @@
         } else {
             assert!(value.is_none(), "`return` and `break` should have a destination");
         }
-        self.exit_scope(source_info.span, region_scope, block, target_block);
+
+        let region_scope = self.scopes.breakable_scopes[break_index].region_scope;
+        let scope_index = self.scopes.scope_index(region_scope, span);
+        let drops = if destination.is_some() {
+            &mut self.scopes.breakable_scopes[break_index].break_drops
+        } else {
+            self.scopes.breakable_scopes[break_index].continue_drops.as_mut().unwrap()
+        };
+        let mut drop_idx = ROOT_NODE;
+        for scope in &self.scopes.scopes[scope_index + 1..] {
+            for drop in &scope.drops {
+                drop_idx = drops.add_drop(*drop, drop_idx);
+            }
+        }
+        drops.add_entry(block, drop_idx);
+
+        // `build_drop_tree` doesn't have access to our source_info, so we
+        // create a dummy terminator now. `TerminatorKind::Resume` is used
+        // because MIR type checking will panic if it hasn't been overwritten.
+        self.cfg.terminate(block, source_info, TerminatorKind::Resume);
+
         self.cfg.start_new_block().unit()
     }
 
-    /// Branch out of `block` to `target`, exiting all scopes up to
-    /// and including `region_scope`. This will insert whatever drops are
-    /// needed. See module comment for details.
-    crate fn exit_scope(
+    crate fn exit_top_scope(
         &mut self,
-        span: Span,
-        region_scope: region::Scope,
         mut block: BasicBlock,
         target: BasicBlock,
+        source_info: SourceInfo,
     ) {
-        debug!(
-            "exit_scope(region_scope={:?}, block={:?}, target={:?})",
-            region_scope, block, target
-        );
-        let scope_count = self.scopes.num_scopes_above(region_scope, span);
-
-        // If we are emitting a `drop` statement, we need to have the cached
-        // diverge cleanup pads ready in case that drop panics.
-        let may_panic = self.scopes.may_panic(scope_count);
-        if may_panic {
-            self.diverge_cleanup();
-        }
-
-        let mut scopes = self.scopes.top_scopes(scope_count + 1).rev();
-        let mut scope = scopes.next().unwrap();
-        for next_scope in scopes {
-            if scope.drops.is_empty() {
-                scope = next_scope;
-                continue;
-            }
-            let source_info = scope.source_info(span);
-            block = match scope.cached_exits.entry((target, region_scope)) {
-                Entry::Occupied(e) => {
-                    self.cfg.goto(block, source_info, *e.get());
-                    return;
-                }
-                Entry::Vacant(v) => {
-                    let b = self.cfg.start_new_block();
-                    self.cfg.goto(block, source_info, b);
-                    v.insert(b);
-                    b
-                }
-            };
-
-            let unwind_to = next_scope.cached_unwind.get(false).unwrap_or_else(|| {
-                debug_assert!(!may_panic, "cached block not present?");
-                START_BLOCK
-            });
-
-            unpack!(
-                block = build_scope_drops(
-                    &mut self.cfg,
-                    self.generator_kind,
-                    scope,
-                    block,
-                    unwind_to,
-                    self.arg_count,
-                    false, // not generator
-                    false, // not unwind path
-                )
-            );
-
-            scope = next_scope;
-        }
-
-        self.cfg.goto(block, self.scopes.source_info(scope_count, span), target);
+        block = self.leave_top_scope(block);
+        self.cfg.terminate(block, source_info, TerminatorKind::Goto { target });
     }
 
-    /// Creates a path that performs all required cleanup for dropping a generator.
-    ///
-    /// This path terminates in GeneratorDrop. Returns the start of the path.
-    /// None indicates there’s no cleanup to do at this point.
-    crate fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
-        // Fill in the cache for unwinds
-        self.diverge_cleanup_gen(true);
+    fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
+        // If we are emitting a `drop` statement, we need to have the cached
+        // diverge cleanup pads ready in case that drop panics.
+        let needs_cleanup = self.scopes.scopes.last().map_or(false, |scope| scope.needs_cleanup());
+        let is_generator = self.generator_kind.is_some();
+        let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX };
 
-        let src_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
-        let resume_block = self.resume_block();
-        let mut scopes = self.scopes.iter_mut().peekable();
-        let mut block = self.cfg.start_new_block();
-        let result = block;
-
-        while let Some(scope) = scopes.next() {
-            block = if let Some(b) = scope.cached_generator_drop {
-                self.cfg.goto(block, src_info, b);
-                return Some(result);
-            } else {
-                let b = self.cfg.start_new_block();
-                scope.cached_generator_drop = Some(b);
-                self.cfg.goto(block, src_info, b);
-                b
-            };
-
-            let unwind_to = scopes
-                .peek()
-                .as_ref()
-                .map(|scope| {
-                    scope
-                        .cached_unwind
-                        .get(true)
-                        .unwrap_or_else(|| span_bug!(src_info.span, "cached block not present?"))
-                })
-                .unwrap_or(resume_block);
-
-            unpack!(
-                block = build_scope_drops(
-                    &mut self.cfg,
-                    self.generator_kind,
-                    scope,
-                    block,
-                    unwind_to,
-                    self.arg_count,
-                    true, // is generator
-                    true, // is cached path
-                )
-            );
-        }
-
-        self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
-
-        Some(result)
+        let scope = self.scopes.scopes.last().expect("leave_top_scope called with no scopes");
+        unpack!(build_scope_drops(
+            &mut self.cfg,
+            &mut self.scopes.unwind_drops,
+            scope,
+            block,
+            unwind_to,
+            is_generator && needs_cleanup,
+            self.arg_count,
+        ))
     }
 
     /// Creates a new source scope, nested in the current one.
@@ -728,15 +749,6 @@
         }
     }
 
-    // Schedule an abort block - this is used for some ABIs that cannot unwind
-    crate fn schedule_abort(&mut self) -> BasicBlock {
-        let source_info = self.scopes.source_info(self.scopes.len(), self.fn_span);
-        let abortblk = self.cfg.start_new_cleanup_block();
-        self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort);
-        self.cached_resume_block = Some(abortblk);
-        abortblk
-    }
-
     // Scheduling drops
     // ================
     crate fn schedule_drop_storage_and_value(
@@ -749,11 +761,10 @@
         self.schedule_drop(span, region_scope, local, DropKind::Value);
     }
 
-    /// Indicates that `place` should be dropped on exit from
-    /// `region_scope`.
+    /// Indicates that `place` should be dropped on exit from `region_scope`.
     ///
-    /// When called with `DropKind::Storage`, `place` should be a local
-    /// with an index higher than the current `self.arg_count`.
+    /// When called with `DropKind::Storage`, `place` shouldn't be the return
+    /// place, or a function parameter.
     crate fn schedule_drop(
         &mut self,
         span: Span,
@@ -781,70 +792,74 @@
             }
         };
 
-        for scope in self.scopes.iter_mut() {
-            let this_scope = scope.region_scope == region_scope;
-            // When building drops, we try to cache chains of drops in such a way so these drops
-            // could be reused by the drops which would branch into the cached (already built)
-            // blocks.  This, however, means that whenever we add a drop into a scope which already
-            // had some blocks built (and thus, cached) for it, we must invalidate all caches which
-            // might branch into the scope which had a drop just added to it. This is necessary,
-            // because otherwise some other code might use the cache to branch into already built
-            // chain of drops, essentially ignoring the newly added drop.
-            //
-            // For example consider there’s two scopes with a drop in each. These are built and
-            // thus the caches are filled:
-            //
-            // +--------------------------------------------------------+
-            // | +---------------------------------+                    |
-            // | | +--------+     +-------------+  |  +---------------+ |
-            // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
-            // | | +--------+     +-------------+  |  +---------------+ |
-            // | +------------|outer_scope cache|--+                    |
-            // +------------------------------|middle_scope cache|------+
-            //
-            // Now, a new, inner-most scope is added along with a new drop into both inner-most and
-            // outer-most scopes:
-            //
-            // +------------------------------------------------------------+
-            // | +----------------------------------+                       |
-            // | | +--------+      +-------------+  |   +---------------+   | +-------------+
-            // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
-            // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
-            // | |             +-+ +-------------+  |                       |
-            // | +---|invalid outer_scope cache|----+                       |
-            // +----=----------------|invalid middle_scope cache|-----------+
-            //
-            // If, when adding `drop(new)` we do not invalidate the cached blocks for both
-            // outer_scope and middle_scope, then, when building drops for the inner (right-most)
-            // scope, the old, cached blocks, without `drop(new)` will get used, producing the
-            // wrong results.
-            //
-            // The cache and its invalidation for unwind branch is somewhat special. The cache is
-            // per-drop, rather than per scope, which has a several different implications. Adding
-            // a new drop into a scope will not invalidate cached blocks of the prior drops in the
-            // scope. That is true, because none of the already existing drops will have an edge
-            // into a block with the newly added drop.
-            //
-            // Note that this code iterates scopes from the inner-most to the outer-most,
-            // invalidating caches of each scope visited. This way bare minimum of the
-            // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
-            // cache of outer scope stays intact.
-            scope.invalidate_cache(!needs_drop, self.generator_kind, this_scope);
-            if this_scope {
+        // When building drops, we try to cache chains of drops to reduce the
+        // number of `DropTree::add_drop` calls. This, however, means that
+        // whenever we add a drop into a scope which already had some entries
+        // in the drop tree built (and thus, cached) for it, we must invalidate
+        // all caches which might branch into the scope which had a drop just
+        // added to it. This is necessary, because otherwise some other code
+        // might use the cache to branch into already built chain of drops,
+        // essentially ignoring the newly added drop.
+        //
+        // For example consider there’s two scopes with a drop in each. These
+        // are built and thus the caches are filled:
+        //
+        // +--------------------------------------------------------+
+        // | +---------------------------------+                    |
+        // | | +--------+     +-------------+  |  +---------------+ |
+        // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
+        // | | +--------+     +-------------+  |  +---------------+ |
+        // | +------------|outer_scope cache|--+                    |
+        // +------------------------------|middle_scope cache|------+
+        //
+        // Now, a new, inner-most scope is added along with a new drop into
+        // both inner-most and outer-most scopes:
+        //
+        // +------------------------------------------------------------+
+        // | +----------------------------------+                       |
+        // | | +--------+      +-------------+  |   +---------------+   | +-------------+
+        // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
+        // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
+        // | |             +-+ +-------------+  |                       |
+        // | +---|invalid outer_scope cache|----+                       |
+        // +----=----------------|invalid middle_scope cache|-----------+
+        //
+        // If, when adding `drop(new)` we do not invalidate the cached blocks for both
+        // outer_scope and middle_scope, then, when building drops for the inner (right-most)
+        // scope, the old, cached blocks, without `drop(new)` will get used, producing the
+        // wrong results.
+        //
+        // Note that this code iterates scopes from the inner-most to the outer-most,
+        // invalidating caches of each scope visited. This way bare minimum of the
+        // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
+        // cache of outer scope stays intact.
+        //
+        // Since we only cache drops for the unwind path and the generator drop
+        // path, we only need to invalidate the cache for drops that happen on
+        // the unwind or generator drop paths. This means that for
+        // non-generators we don't need to invalidate caches for `DropKind::Storage`.
+        let invalidate_caches = needs_drop || self.generator_kind.is_some();
+        for scope in self.scopes.scopes.iter_mut().rev() {
+            if invalidate_caches {
+                scope.invalidate_cache();
+            }
+
+            if scope.region_scope == region_scope {
                 let region_scope_span =
                     region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree);
                 // Attribute scope exit drops to scope's closing brace.
                 let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span);
 
                 scope.drops.push(DropData {
-                    span: scope_end,
+                    source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
                     local,
                     kind: drop_kind,
-                    cached_block: CachedBlock::default(),
                 });
+
                 return;
             }
         }
+
         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
     }
 
@@ -893,8 +908,9 @@
 
             Some(local_scope) => self
                 .scopes
+                .scopes
                 .iter_mut()
-                .find(|scope| scope.region_scope == local_scope)
+                .rfind(|scope| scope.region_scope == local_scope)
                 .unwrap_or_else(|| bug!("scope {:?} not found in scope list!", local_scope)),
         };
 
@@ -944,13 +960,16 @@
                     // Manually drop the condition on both branches.
                     let top_scope = self.scopes.scopes.last_mut().unwrap();
                     let top_drop_data = top_scope.drops.pop().unwrap();
+                    if self.generator_kind.is_some() {
+                        top_scope.invalidate_cache();
+                    }
 
                     match top_drop_data.kind {
                         DropKind::Value { .. } => {
                             bug!("Drop scheduled on top of condition variable")
                         }
                         DropKind::Storage => {
-                            let source_info = top_scope.source_info(top_drop_data.span);
+                            let source_info = top_drop_data.source_info;
                             let local = top_drop_data.local;
                             assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
                             self.cfg.push(
@@ -963,8 +982,6 @@
                             );
                         }
                     }
-
-                    top_scope.invalidate_cache(true, self.generator_kind, true);
                 } else {
                     bug!("Expected as_local_operand to produce a temporary");
                 }
@@ -974,62 +991,86 @@
         (true_block, false_block)
     }
 
-    /// Creates a path that performs all required cleanup for unwinding.
+    /// Returns the [DropIdx] for the innermost drop if the function unwound at
+    /// this point. The `DropIdx` will be created if it doesn't already exist.
+    fn diverge_cleanup(&mut self) -> DropIdx {
+        let is_generator = self.generator_kind.is_some();
+        let (uncached_scope, mut cached_drop) = self
+            .scopes
+            .scopes
+            .iter()
+            .enumerate()
+            .rev()
+            .find_map(|(scope_idx, scope)| {
+                scope.cached_unwind_block.map(|cached_block| (scope_idx + 1, cached_block))
+            })
+            .unwrap_or((0, ROOT_NODE));
+
+        for scope in &mut self.scopes.scopes[uncached_scope..] {
+            for drop in &scope.drops {
+                if is_generator || drop.kind == DropKind::Value {
+                    cached_drop = self.scopes.unwind_drops.add_drop(*drop, cached_drop);
+                }
+            }
+            scope.cached_unwind_block = Some(cached_drop);
+        }
+
+        cached_drop
+    }
+
+    /// Prepares to create a path that performs all required cleanup for a
+    /// terminator that can unwind at the given basic block.
     ///
-    /// This path terminates in Resume. Returns the start of the path.
-    /// See module comment for more details.
-    crate fn diverge_cleanup(&mut self) -> BasicBlock {
-        self.diverge_cleanup_gen(false)
+    /// This path terminates in Resume. The path isn't created until after all
+    /// of the non-unwind paths in this item have been lowered.
+    crate fn diverge_from(&mut self, start: BasicBlock) {
+        debug_assert!(
+            matches!(
+                self.cfg.block_data(start).terminator().kind,
+                TerminatorKind::Assert { .. }
+                | TerminatorKind::Call {..}
+                | TerminatorKind::DropAndReplace { .. }
+                | TerminatorKind::FalseUnwind { .. }
+            ),
+            "diverge_from called on block with terminator that cannot unwind."
+        );
+
+        let next_drop = self.diverge_cleanup();
+        self.scopes.unwind_drops.add_entry(start, next_drop);
     }
 
-    fn resume_block(&mut self) -> BasicBlock {
-        if let Some(target) = self.cached_resume_block {
-            target
-        } else {
-            let resumeblk = self.cfg.start_new_cleanup_block();
-            self.cfg.terminate(
-                resumeblk,
-                SourceInfo::outermost(self.fn_span),
-                TerminatorKind::Resume,
-            );
-            self.cached_resume_block = Some(resumeblk);
-            resumeblk
-        }
-    }
+    /// Sets up a path that performs all required cleanup for dropping a
+    /// generator, starting from the given block that ends in
+    /// [TerminatorKind::Yield].
+    ///
+    /// This path terminates in GeneratorDrop.
+    crate fn generator_drop_cleanup(&mut self, yield_block: BasicBlock) {
+        debug_assert!(
+            matches!(
+                self.cfg.block_data(yield_block).terminator().kind,
+                TerminatorKind::Yield { .. }
+            ),
+            "generator_drop_cleanup called on block with non-yield terminator."
+        );
+        let (uncached_scope, mut cached_drop) = self
+            .scopes
+            .scopes
+            .iter()
+            .enumerate()
+            .rev()
+            .find_map(|(scope_idx, scope)| {
+                scope.cached_generator_drop_block.map(|cached_block| (scope_idx + 1, cached_block))
+            })
+            .unwrap_or((0, ROOT_NODE));
 
-    fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
-        // Build up the drops in **reverse** order. The end result will
-        // look like:
-        //
-        //    scopes[n] -> scopes[n-1] -> ... -> scopes[0]
-        //
-        // However, we build this in **reverse order**. That is, we
-        // process scopes[0], then scopes[1], etc, pointing each one at
-        // the result generates from the one before. Along the way, we
-        // store caches. If everything is cached, we'll just walk right
-        // to left reading the cached results but never created anything.
-
-        // Find the last cached block
-        debug!("diverge_cleanup_gen(self.scopes = {:?})", self.scopes);
-        let cached_cleanup = self.scopes.iter_mut().enumerate().find_map(|(idx, ref scope)| {
-            let cached_block = scope.cached_unwind.get(generator_drop)?;
-            Some((cached_block, idx))
-        });
-        let (mut target, first_uncached) =
-            cached_cleanup.unwrap_or_else(|| (self.resume_block(), self.scopes.len()));
-
-        for scope in self.scopes.top_scopes(first_uncached) {
-            target = build_diverge_scope(
-                &mut self.cfg,
-                scope.region_scope_span,
-                scope,
-                target,
-                generator_drop,
-                self.generator_kind,
-            );
+        for scope in &mut self.scopes.scopes[uncached_scope..] {
+            for drop in &scope.drops {
+                cached_drop = self.scopes.generator_drops.add_drop(*drop, cached_drop);
+            }
+            scope.cached_generator_drop_block = Some(cached_drop);
         }
 
-        target
+        self.scopes.generator_drops.add_entry(yield_block, cached_drop);
     }
 
     /// Utility function for *non*-scope code to build their own drops
@@ -1042,21 +1083,18 @@
     ) -> BlockAnd<()> {
         let source_info = self.source_info(span);
         let next_target = self.cfg.start_new_block();
-        let diverge_target = self.diverge_cleanup();
+
         self.cfg.terminate(
             block,
             source_info,
-            TerminatorKind::DropAndReplace {
-                place,
-                value,
-                target: next_target,
-                unwind: Some(diverge_target),
-            },
+            TerminatorKind::DropAndReplace { place, value, target: next_target, unwind: None },
         );
+        self.diverge_from(block);
+
         next_target.unit()
     }
 
-    /// Creates an Assert terminator and return the success block.
+    /// Creates an `Assert` terminator and return the success block.
     /// If the boolean condition operand is not the expected value,
     /// a runtime panic will be caused with the given message.
     crate fn assert(
@@ -1068,51 +1106,41 @@
         span: Span,
     ) -> BasicBlock {
         let source_info = self.source_info(span);
-
         let success_block = self.cfg.start_new_block();
-        let cleanup = self.diverge_cleanup();
 
         self.cfg.terminate(
             block,
             source_info,
-            TerminatorKind::Assert {
-                cond,
-                expected,
-                msg,
-                target: success_block,
-                cleanup: Some(cleanup),
-            },
+            TerminatorKind::Assert { cond, expected, msg, target: success_block, cleanup: None },
         );
+        self.diverge_from(block);
 
         success_block
     }
 
-    // `match` arm scopes
-    // ==================
     /// Unschedules any drops in the top scope.
     ///
     /// This is only needed for `match` arm scopes, because they have one
     /// entrance per pattern, but only one exit.
-    pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) {
+    crate fn clear_top_scope(&mut self, region_scope: region::Scope) {
         let top_scope = self.scopes.scopes.last_mut().unwrap();
 
         assert_eq!(top_scope.region_scope, region_scope);
 
         top_scope.drops.clear();
-        top_scope.invalidate_cache(false, self.generator_kind, true);
+        top_scope.invalidate_cache();
     }
 }
 
-/// Builds drops for pop_scope and exit_scope.
+/// Builds drops for `pop_scope` and `leave_top_scope`.
 fn build_scope_drops<'tcx>(
     cfg: &mut CFG<'tcx>,
-    generator_kind: Option<GeneratorKind>,
+    unwind_drops: &mut DropTree,
     scope: &Scope,
     mut block: BasicBlock,
-    last_unwind_to: BasicBlock,
+    mut unwind_to: DropIdx,
+    storage_dead_on_unwind: bool,
     arg_count: usize,
-    generator_drop: bool,
-    is_cached_path: bool,
 ) -> BlockAnd<()> {
     debug!("build_scope_drops({:?} -> {:?})", block, scope);
 
@@ -1135,37 +1163,43 @@
     // drops for the unwind path should have already been generated by
     // `diverge_cleanup_gen`.
 
-    for drop_idx in (0..scope.drops.len()).rev() {
-        let drop_data = &scope.drops[drop_idx];
-        let source_info = scope.source_info(drop_data.span);
+    for drop_data in scope.drops.iter().rev() {
+        let source_info = drop_data.source_info;
         let local = drop_data.local;
 
         match drop_data.kind {
             DropKind::Value => {
+                // `unwind_to` should drop the value that we're about to
+                // schedule. If dropping this value panics, then we continue
+                // with the *next* value on the unwind path.
+                debug_assert_eq!(unwind_drops.drops[unwind_to].0.local, drop_data.local);
+                debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
+                unwind_to = unwind_drops.drops[unwind_to].1;
+
                 // If the operand has been moved, and we are not on an unwind
                 // path, then don't generate the drop. (We only take this into
                 // account for non-unwind paths so as not to disturb the
                 // caching mechanism.)
-                if !is_cached_path && scope.moved_locals.iter().any(|&o| o == local) {
+                if scope.moved_locals.iter().any(|&o| o == local) {
                     continue;
                 }
 
-                let unwind_to = get_unwind_to(scope, generator_kind, drop_idx, generator_drop)
-                    .unwrap_or(last_unwind_to);
+                unwind_drops.add_entry(block, unwind_to);
 
                 let next = cfg.start_new_block();
                 cfg.terminate(
                     block,
                     source_info,
-                    TerminatorKind::Drop {
-                        place: local.into(),
-                        target: next,
-                        unwind: Some(unwind_to),
-                    },
+                    TerminatorKind::Drop { place: local.into(), target: next, unwind: None },
                 );
                 block = next;
             }
             DropKind::Storage => {
+                if storage_dead_on_unwind {
+                    debug_assert_eq!(unwind_drops.drops[unwind_to].0.local, drop_data.local);
+                    debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
+                    unwind_to = unwind_drops.drops[unwind_to].1;
+                }
                 // Only temps and vars need their storage dead.
                 assert!(local.index() > arg_count);
                 cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) });
@@ -1175,139 +1209,189 @@
     block.unit()
 }
 
-fn get_unwind_to(
-    scope: &Scope,
-    generator_kind: Option<GeneratorKind>,
-    unwind_from: usize,
-    generator_drop: bool,
-) -> Option<BasicBlock> {
-    for drop_idx in (0..unwind_from).rev() {
-        let drop_data = &scope.drops[drop_idx];
-        match (generator_kind, &drop_data.kind) {
-            (Some(_), DropKind::Storage) => {
-                return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
-                    span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
-                }));
+impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
+    /// Build a drop tree for a breakable scope.
+    ///
+    /// If `continue_block` is `Some`, then the tree is for `continue` inside a
+    /// loop. Otherwise this is for `break` or `return`.
+    fn build_exit_tree(
+        &mut self,
+        mut drops: DropTree,
+        continue_block: Option<BasicBlock>,
+    ) -> Option<BlockAnd<()>> {
+        let mut blocks = IndexVec::from_elem(None, &drops.drops);
+        blocks[ROOT_NODE] = continue_block;
+
+        drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks);
+
+        // Link the exit drop tree to unwind drop tree.
+        if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) {
+            let unwind_target = self.diverge_cleanup();
+            let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
+            for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) {
+                match drop_data.0.kind {
+                    DropKind::Storage => {
+                        if self.generator_kind.is_some() {
+                            let unwind_drop = self
+                                .scopes
+                                .unwind_drops
+                                .add_drop(drop_data.0, unwind_indices[drop_data.1]);
+                            unwind_indices.push(unwind_drop);
+                        } else {
+                            unwind_indices.push(unwind_indices[drop_data.1]);
+                        }
+                    }
+                    DropKind::Value => {
+                        let unwind_drop = self
+                            .scopes
+                            .unwind_drops
+                            .add_drop(drop_data.0, unwind_indices[drop_data.1]);
+                        self.scopes
+                            .unwind_drops
+                            .add_entry(blocks[drop_idx].unwrap(), unwind_indices[drop_data.1]);
+                        unwind_indices.push(unwind_drop);
+                    }
+                }
             }
-            (None, DropKind::Value) => {
-                return Some(drop_data.cached_block.get(generator_drop).unwrap_or_else(|| {
-                    span_bug!(drop_data.span, "cached block not present for {:?}", drop_data)
-                }));
-            }
-            _ => (),
+        }
+        blocks[ROOT_NODE].map(BasicBlock::unit)
+    }
+
+    /// Build the unwind and generator drop trees.
+    crate fn build_drop_trees(&mut self, should_abort: bool) {
+        if self.generator_kind.is_some() {
+            self.build_generator_drop_trees(should_abort);
+        } else {
+            Self::build_unwind_tree(
+                &mut self.cfg,
+                &mut self.scopes.unwind_drops,
+                self.fn_span,
+                should_abort,
+                &mut None,
+            );
         }
     }
-    None
-}
 
-fn build_diverge_scope<'tcx>(
-    cfg: &mut CFG<'tcx>,
-    span: Span,
-    scope: &mut Scope,
-    mut target: BasicBlock,
-    generator_drop: bool,
-    generator_kind: Option<GeneratorKind>,
-) -> BasicBlock {
-    // Build up the drops in **reverse** order. The end result will
-    // look like:
-    //
-    //    [drops[n]] -...-> [drops[0]] -> [target]
-    //
-    // The code in this function reads from right to left. At each
-    // point, we check for cached blocks representing the
-    // remainder. If everything is cached, we'll just walk right to
-    // left reading the cached results but never create anything.
+    fn build_generator_drop_trees(&mut self, should_abort: bool) {
+        // Build the drop tree for dropping the generator while it's suspended.
+        let drops = &mut self.scopes.generator_drops;
+        let cfg = &mut self.cfg;
+        let fn_span = self.fn_span;
+        let mut blocks = IndexVec::from_elem(None, &drops.drops);
+        drops.build_mir::<GeneratorDrop>(cfg, &mut blocks);
+        if let Some(root_block) = blocks[ROOT_NODE] {
+            cfg.terminate(
+                root_block,
+                SourceInfo::outermost(fn_span),
+                TerminatorKind::GeneratorDrop,
+            );
+        }
 
-    let source_scope = scope.source_scope;
-    let source_info = |span| SourceInfo { span, scope: source_scope };
+        // Build the drop tree for unwinding in the normal control flow paths.
+        let resume_block = &mut None;
+        let unwind_drops = &mut self.scopes.unwind_drops;
+        Self::build_unwind_tree(cfg, unwind_drops, fn_span, should_abort, resume_block);
 
-    // We keep track of StorageDead statements to prepend to our current block
-    // and store them here, in reverse order.
-    let mut storage_deads = vec![];
-
-    let mut target_built_by_us = false;
-
-    // Build up the drops. Here we iterate the vector in
-    // *forward* order, so that we generate drops[0] first (right to
-    // left in diagram above).
-    debug!("build_diverge_scope({:?})", scope.drops);
-    for (j, drop_data) in scope.drops.iter_mut().enumerate() {
-        debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data);
-        // Only full value drops are emitted in the diverging path,
-        // not StorageDead, except in the case of generators.
+        // Build the drop tree for unwinding when dropping a suspended
+        // generator.
         //
-        // Note: This may not actually be what we desire (are we
-        // "freeing" stack storage as we unwind, or merely observing a
-        // frozen stack)? In particular, the intent may have been to
-        // match the behavior of clang, but on inspection eddyb says
-        // this is not what clang does.
-        match drop_data.kind {
-            DropKind::Storage if generator_kind.is_some() => {
-                storage_deads.push(Statement {
-                    source_info: source_info(drop_data.span),
-                    kind: StatementKind::StorageDead(drop_data.local),
-                });
-                if !target_built_by_us {
-                    // We cannot add statements to an existing block, so we create a new
-                    // block for our StorageDead statements.
-                    let block = cfg.start_new_cleanup_block();
-                    let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope };
-                    cfg.goto(block, source_info, target);
-                    target = block;
-                    target_built_by_us = true;
-                }
-                *drop_data.cached_block.ref_mut(generator_drop) = Some(target);
+        // This is a different tree to the standard unwind paths here to
+        // prevent drop elaboration from creating drop flags that would have
+        // to be captured by the generator. I'm not sure how important this
+        // optimization is, but it is here.
+        for (drop_idx, drop_data) in drops.drops.iter_enumerated() {
+            if let DropKind::Value = drop_data.0.kind {
+                debug_assert!(drop_data.1 < drops.drops.next_index());
+                drops.entry_points.push((drop_data.1, blocks[drop_idx].unwrap()));
             }
-            DropKind::Storage => {}
-            DropKind::Value => {
-                let cached_block = drop_data.cached_block.ref_mut(generator_drop);
-                target = if let Some(cached_block) = *cached_block {
-                    storage_deads.clear();
-                    target_built_by_us = false;
-                    cached_block
-                } else {
-                    push_storage_deads(cfg, target, &mut storage_deads);
-                    let block = cfg.start_new_cleanup_block();
-                    cfg.terminate(
-                        block,
-                        source_info(drop_data.span),
-                        TerminatorKind::Drop {
-                            place: drop_data.local.into(),
-                            target,
-                            unwind: None,
-                        },
-                    );
-                    *cached_block = Some(block);
-                    target_built_by_us = true;
-                    block
-                };
-            }
-        };
+        }
+        Self::build_unwind_tree(cfg, drops, fn_span, should_abort, resume_block);
     }
-    push_storage_deads(cfg, target, &mut storage_deads);
-    *scope.cached_unwind.ref_mut(generator_drop) = Some(target);
 
-    assert!(storage_deads.is_empty());
-    debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
+    fn build_unwind_tree(
+        cfg: &mut CFG<'tcx>,
+        drops: &mut DropTree,
+        fn_span: Span,
+        should_abort: bool,
+        resume_block: &mut Option<BasicBlock>,
+    ) {
+        let mut blocks = IndexVec::from_elem(None, &drops.drops);
+        blocks[ROOT_NODE] = *resume_block;
+        drops.build_mir::<Unwind>(cfg, &mut blocks);
+        if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) {
+            // `TerminatorKind::Abort` is used for `#[unwind(aborts)]`
+            // functions.
+            let terminator =
+                if should_abort { TerminatorKind::Abort } else { TerminatorKind::Resume };
 
-    target
+            cfg.terminate(resume, SourceInfo::outermost(fn_span), terminator);
+
+            *resume_block = blocks[ROOT_NODE];
+        }
+    }
 }
 
-fn push_storage_deads<'tcx>(
-    cfg: &mut CFG<'tcx>,
-    target: BasicBlock,
-    storage_deads: &mut Vec<Statement<'tcx>>,
-) {
-    if storage_deads.is_empty() {
-        return;
+// DropTreeBuilder implementations.
+
+struct ExitScopes;
+
+impl<'tcx> DropTreeBuilder<'tcx> for ExitScopes {
+    fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock {
+        cfg.start_new_block()
     }
-    let statements = &mut cfg.block_data_mut(target).statements;
-    storage_deads.reverse();
-    debug!(
-        "push_storage_deads({:?}), storage_deads={:?}, statements={:?}",
-        target, storage_deads, statements
-    );
-    storage_deads.append(statements);
-    mem::swap(statements, storage_deads);
-    assert!(storage_deads.is_empty());
+    fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
+        cfg.block_data_mut(from).terminator_mut().kind = TerminatorKind::Goto { target: to };
+    }
+}
+
+struct GeneratorDrop;
+
+impl<'tcx> DropTreeBuilder<'tcx> for GeneratorDrop {
+    fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock {
+        cfg.start_new_block()
+    }
+    fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
+        let term = cfg.block_data_mut(from).terminator_mut();
+        if let TerminatorKind::Yield { ref mut drop, .. } = term.kind {
+            *drop = Some(to);
+        } else {
+            span_bug!(
+                term.source_info.span,
+                "cannot enter generator drop tree from {:?}",
+                term.kind
+            )
+        }
+    }
+}
+
+struct Unwind;
+
+impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
+    fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock {
+        cfg.start_new_cleanup_block()
+    }
+    fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
+        let term = &mut cfg.block_data_mut(from).terminator_mut();
+        match &mut term.kind {
+            TerminatorKind::Drop { unwind, .. }
+            | TerminatorKind::DropAndReplace { unwind, .. }
+            | TerminatorKind::FalseUnwind { unwind, .. }
+            | TerminatorKind::Call { cleanup: unwind, .. }
+            | TerminatorKind::Assert { cleanup: unwind, .. } => {
+                *unwind = Some(to);
+            }
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::Resume
+            | TerminatorKind::Abort
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::Yield { .. }
+            | TerminatorKind::GeneratorDrop
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::InlineAsm {.. } => {
+                span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind)
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index a8d7c61..a9620b8 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -1,7 +1,6 @@
 use rustc_data_structures::graph::iterate::{
     ControlFlow, NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
-use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_middle::hir::map::blocks::FnLikeNode;
 use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
@@ -10,7 +9,8 @@
 use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
 use rustc_span::Span;
 
-crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: LocalDefId) {
+crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+    let def_id = body.source.def_id().expect_local();
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
     if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir().get(hir_id)) {
@@ -30,7 +30,7 @@
             _ => &[],
         };
 
-        let mut vis = Search { tcx, body, def_id, reachable_recursive_calls: vec![], trait_substs };
+        let mut vis = Search { tcx, body, reachable_recursive_calls: vec![], trait_substs };
         if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
             return;
         }
@@ -57,7 +57,6 @@
 struct Search<'mir, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'mir Body<'tcx>,
-    def_id: LocalDefId,
     trait_substs: &'tcx [GenericArg<'tcx>],
 
     reachable_recursive_calls: Vec<Span>,
@@ -66,17 +65,20 @@
 impl<'mir, 'tcx> Search<'mir, 'tcx> {
     /// Returns `true` if `func` refers to the function we are searching in.
     fn is_recursive_call(&self, func: &Operand<'tcx>) -> bool {
-        let Search { tcx, body, def_id, trait_substs, .. } = *self;
-        let param_env = tcx.param_env(def_id);
+        let Search { tcx, body, trait_substs, .. } = *self;
+        let caller = body.source.def_id();
+        let param_env = tcx.param_env(caller);
 
         let func_ty = func.ty(body, tcx);
-        if let ty::FnDef(fn_def_id, substs) = *func_ty.kind() {
-            let (call_fn_id, call_substs) =
-                if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, fn_def_id, substs) {
-                    (instance.def_id(), instance.substs)
-                } else {
-                    (fn_def_id, substs)
-                };
+        if let ty::FnDef(callee, substs) = *func_ty.kind() {
+            let normalized_substs = tcx.normalize_erasing_regions(param_env, substs);
+            let (callee, call_substs) = if let Ok(Some(instance)) =
+                Instance::resolve(tcx, param_env, callee, normalized_substs)
+            {
+                (instance.def_id(), instance.substs)
+            } else {
+                (callee, normalized_substs)
+            };
 
             // FIXME(#57965): Make this work across function boundaries
 
@@ -84,8 +86,7 @@
             // calling into an entirely different method (for example, a call from the default
             // method in the trait to `<A as Trait<B>>::method`, where `A` and/or `B` are
             // specific types).
-            return call_fn_id == def_id.to_def_id()
-                && &call_substs[..trait_substs.len()] == trait_substs;
+            return callee == caller && &call_substs[..trait_substs.len()] == trait_substs;
         }
 
         false
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index a7bb286..b71ff6e 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -31,7 +31,7 @@
         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
             if matches!(inner_ty.kind(), ty::Slice(_)) =>
         {
-            let allocation = Allocation::from_byte_aligned_bytes(data as &Vec<u8>);
+            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
             let allocation = tcx.intern_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: data.len() }
         }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 13e6947..731bd95 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -511,6 +511,12 @@
             inputs: asm.inputs_exprs.to_ref(),
         },
 
+        hir::ExprKind::ConstBlock(ref anon_const) => {
+            let anon_const_def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
+            let value = ty::Const::from_anon_const(cx.tcx, anon_const_def_id);
+
+            ExprKind::ConstBlock { value }
+        }
         // Now comes the rote stuff:
         hir::ExprKind::Repeat(ref v, ref count) => {
             let count_def_id = cx.tcx.hir().local_def_id(count.hir_id);
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index 4d57fd5..f2a2ef0 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -232,6 +232,9 @@
     Return {
         value: Option<ExprRef<'tcx>>,
     },
+    ConstBlock {
+        value: &'tcx Const<'tcx>,
+    },
     Repeat {
         value: ExprRef<'tcx>,
         count: &'tcx Const<'tcx>,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index 904524e..7216d13 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -78,20 +78,26 @@
 //! new pattern `p`.
 //!
 //! For example, say we have the following:
+//!
 //! ```
-//!     // x: (Option<bool>, Result<()>)
-//!     match x {
-//!         (Some(true), _) => {}
-//!         (None, Err(())) => {}
-//!         (None, Err(_)) => {}
-//!     }
+//! // x: (Option<bool>, Result<()>)
+//! match x {
+//!     (Some(true), _) => {}
+//!     (None, Err(())) => {}
+//!     (None, Err(_)) => {}
+//! }
 //! ```
+//!
 //! Here, the matrix `P` starts as:
+//!
+//! ```
 //! [
 //!     [(Some(true), _)],
 //!     [(None, Err(()))],
 //!     [(None, Err(_))],
 //! ]
+//! ```
+//!
 //! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
 //! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
 //! all the values it covers are already covered by row 2.
@@ -178,10 +184,14 @@
 //! This special case is handled in `is_useful_specialized`.
 //!
 //! For example, if `P` is:
+//!
+//! ```
 //! [
-//! [Some(true), _],
-//! [None, 0],
+//!     [Some(true), _],
+//!     [None, 0],
 //! ]
+//! ```
+//!
 //! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
 //! matches values that row 2 doesn't. For row 1 however, we need to dig into the
 //! arguments of `Some` to know whether some new value is covered. So we compute
@@ -198,10 +208,14 @@
 //! `U(P, p) := U(D(P), D(p))`
 //!
 //! For example, if `P` is:
+//!
+//! ```
 //! [
 //!     [_, true, _],
 //!     [None, false, 1],
 //! ]
+//! ```
+//!
 //! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
 //! only had row 2, we'd know that `p` is useful. However row 1 starts with a
 //! wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
@@ -215,10 +229,14 @@
 //! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
 //!
 //! For example, if `P` is:
+//!
+//! ```
 //! [
 //!     [Some(true), _],
 //!     [None, false],
 //! ]
+//! ```
+//!
 //! and `p` is [_, false], both `None` and `Some` constructors appear in the first
 //! components of `P`. We will therefore try popping both constructors in turn: we
 //! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]],
@@ -1496,6 +1514,7 @@
 /// multiple patterns.
 ///
 /// For example, if we are constructing a witness for the match against
+///
 /// ```
 /// struct Pair(Option<(u32, u32)>, bool);
 ///
@@ -1619,12 +1638,14 @@
             // actually match against them all themselves. So we always return only the fictitious
             // constructor.
             // E.g., in an example like:
+            //
             // ```
             //     let err: io::ErrorKind = ...;
             //     match err {
             //         io::ErrorKind::NotFound => {},
             //     }
             // ```
+            //
             // we don't want to show every possible IO error, but instead have only `_` as the
             // witness.
             let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
@@ -1787,9 +1808,32 @@
         param_env: ty::ParamEnv<'tcx>,
         pat: &Pat<'tcx>,
     ) -> Option<IntRange<'tcx>> {
-        match pat_constructor(tcx, param_env, pat)? {
-            IntRange(range) => Some(range),
-            _ => None,
+        // This MUST be kept in sync with `pat_constructor`.
+        match *pat.kind {
+            PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
+            PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."),
+
+            PatKind::Binding { .. }
+            | PatKind::Wild
+            | PatKind::Leaf { .. }
+            | PatKind::Deref { .. }
+            | PatKind::Variant { .. }
+            | PatKind::Array { .. }
+            | PatKind::Slice { .. } => None,
+
+            PatKind::Constant { value } => Self::from_const(tcx, param_env, value, pat.span),
+
+            PatKind::Range(PatRange { lo, hi, end }) => {
+                let ty = lo.ty;
+                Self::from_range(
+                    tcx,
+                    lo.eval_bits(tcx, param_env, lo.ty),
+                    hi.eval_bits(tcx, param_env, hi.ty),
+                    ty,
+                    &end,
+                    pat.span,
+                )
+            }
         }
     }
 
@@ -1994,6 +2038,7 @@
         let mut unreachable_branches = Vec::new();
         // Subpatterns that are unreachable from all branches. E.g. in the following case, the last
         // `true` is unreachable only from one branch, so it is overall reachable.
+        //
         // ```
         // match (true, true) {
         //     (true, true) => {}
@@ -2138,10 +2183,12 @@
             // to do this and instead report a single `_` witness:
             // if the user didn't actually specify a constructor
             // in this arm, e.g., in
+            //
             // ```
             //     let x: (Direction, Direction, bool) = ...;
             //     let (_, _, false) = x;
             // ```
+            //
             // we don't want to show all 16 possible witnesses
             // `(<direction-1>, <direction-2>, true)` - we are
             // satisfied with `(_, _, true)`. In this case,
@@ -2196,6 +2243,7 @@
     param_env: ty::ParamEnv<'tcx>,
     pat: &Pat<'tcx>,
 ) -> Option<Constructor<'tcx>> {
+    // This MUST be kept in sync with `IntRange::from_pat`.
     match *pat.kind {
         PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern`
         PatKind::Binding { .. } | PatKind::Wild => None,
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 047bf7d..69de7c7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -71,13 +71,13 @@
             hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
         };
         self.check_irrefutable(&loc.pat, msg, sp);
-        self.check_patterns(false, &loc.pat);
+        self.check_patterns(&loc.pat);
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
         intravisit::walk_param(self, param);
         self.check_irrefutable(&param.pat, "function argument", None);
-        self.check_patterns(false, &param.pat);
+        self.check_patterns(&param.pat);
     }
 }
 
@@ -96,14 +96,14 @@
                 }
                 PatternError::FloatBug => {
                     // FIXME(#31407) this is only necessary because float parsing is buggy
-                    ::rustc_middle::mir::interpret::struct_error(
+                    rustc_middle::mir::interpret::struct_error(
                         self.tcx.at(pat_span),
                         "could not evaluate float literal (see issue #31407)",
                     )
                     .emit();
                 }
                 PatternError::NonConstPath(span) => {
-                    ::rustc_middle::mir::interpret::struct_error(
+                    rustc_middle::mir::interpret::struct_error(
                         self.tcx.at(span),
                         "runtime values cannot be referenced in patterns",
                     )
@@ -119,10 +119,7 @@
 }
 
 impl<'tcx> MatchVisitor<'_, 'tcx> {
-    fn check_patterns(&mut self, has_guard: bool, pat: &Pat<'_>) {
-        if !self.tcx.features().move_ref_pattern {
-            check_legality_of_move_bindings(self, has_guard, pat);
-        }
+    fn check_patterns(&mut self, pat: &Pat<'_>) {
         pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
         if !self.tcx.features().bindings_after_at {
             check_legality_of_bindings_in_at_patterns(self, pat);
@@ -165,7 +162,7 @@
     ) {
         for arm in arms {
             // Check the arm for some things unrelated to exhaustiveness.
-            self.check_patterns(arm.guard.is_some(), &arm.pat);
+            self.check_patterns(&arm.pat);
         }
 
         let mut cx = self.new_cx(scrut.hir_id);
@@ -601,65 +598,6 @@
     !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
 }
 
-/// Check the legality of legality of by-move bindings.
-fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat<'_>) {
-    let sess = cx.tcx.sess;
-    let typeck_results = cx.typeck_results;
-
-    // Find all by-ref spans.
-    let mut by_ref_spans = Vec::new();
-    pat.each_binding(|_, hir_id, span, _| {
-        if let Some(ty::BindByReference(_)) =
-            typeck_results.extract_binding_mode(sess, hir_id, span)
-        {
-            by_ref_spans.push(span);
-        }
-    });
-
-    // Find bad by-move spans:
-    let by_move_spans = &mut Vec::new();
-    let mut check_move = |p: &Pat<'_>, sub: Option<&Pat<'_>>| {
-        // Check legality of moving out of the enum.
-        //
-        // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't.
-        if sub.map_or(false, |p| p.contains_bindings()) {
-            struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings")
-                .span_label(p.span, "binds an already bound by-move value by moving it")
-                .emit();
-        } else if !has_guard && !by_ref_spans.is_empty() {
-            by_move_spans.push(p.span);
-        }
-    };
-    pat.walk_always(|p| {
-        if let hir::PatKind::Binding(.., sub) = &p.kind {
-            if let Some(ty::BindByValue(_)) =
-                typeck_results.extract_binding_mode(sess, p.hir_id, p.span)
-            {
-                if is_binding_by_move(cx, p.hir_id, p.span) {
-                    check_move(p, sub.as_deref());
-                }
-            }
-        }
-    });
-
-    // Found some bad by-move spans, error!
-    if !by_move_spans.is_empty() {
-        let mut err = feature_err(
-            &sess.parse_sess,
-            sym::move_ref_pattern,
-            by_move_spans.clone(),
-            "binding by-move and by-ref in the same pattern is unstable",
-        );
-        for span in by_ref_spans.iter() {
-            err.span_label(*span, "by-ref pattern here");
-        }
-        for span in by_move_spans.iter() {
-            err.span_label(*span, "by-move pattern here");
-        }
-        err.emit();
-    }
-}
-
 /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
 ///
 /// For example, this would reject:
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 718ed78..b05ddb3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -856,6 +856,11 @@
             *self.lower_path(qpath, expr.hir_id, expr.span).kind
         } else {
             let (lit, neg) = match expr.kind {
+                hir::ExprKind::ConstBlock(ref anon_const) => {
+                    let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+                    let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                    return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind;
+                }
                 hir::ExprKind::Lit(ref lit) => (lit, false),
                 hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
                     let lit = match expr.kind {
@@ -1060,13 +1065,13 @@
         use rustc_apfloat::Float;
         return match *ty.kind() {
             ty::Float(ast::FloatTy::F32) => {
-                let l = ::rustc_apfloat::ieee::Single::from_bits(a);
-                let r = ::rustc_apfloat::ieee::Single::from_bits(b);
+                let l = rustc_apfloat::ieee::Single::from_bits(a);
+                let r = rustc_apfloat::ieee::Single::from_bits(b);
                 l.partial_cmp(&r)
             }
             ty::Float(ast::FloatTy::F64) => {
-                let l = ::rustc_apfloat::ieee::Double::from_bits(a);
-                let r = ::rustc_apfloat::ieee::Double::from_bits(b);
+                let l = rustc_apfloat::ieee::Double::from_bits(a);
+                let r = rustc_apfloat::ieee::Double::from_bits(b);
                 l.partial_cmp(&r)
             }
             ty::Int(ity) => {
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 6f249f4..47d317f 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -181,10 +181,9 @@
 
             if suggestion_len > 0 {
                 suggestion.push('}');
-                let lo = char_span.lo();
-                let hi = lo + BytePos(suggestion_len as u32);
+                let hi = char_span.lo() + BytePos(suggestion_len as u32);
                 diag.span_suggestion(
-                    span.with_lo(lo).with_hi(hi),
+                    span.with_hi(hi),
                     "format of unicode escape sequences uses braces",
                     suggestion,
                     Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index d59dd40..e073f57 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -7,8 +7,8 @@
 #![feature(or_patterns)]
 
 use rustc_ast as ast;
-use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{self, Spacing, TokenStream, TokenTree};
+use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
+use rustc_ast::tokenstream::{self, LazyTokenStream, TokenStream, TokenTree};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diagnostic, FatalError, Level, PResult};
@@ -22,7 +22,7 @@
 
 use tracing::{debug, info};
 
-pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
+pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
 
 #[macro_use]
 pub mod parser;
@@ -114,16 +114,6 @@
     source_file_to_parser(sess, file_to_source_file(sess, path, sp))
 }
 
-/// Creates a new parser, returning buffered diagnostics if the file doesn't exist,
-/// or from lexing the initial token stream.
-pub fn maybe_new_parser_from_file<'a>(
-    sess: &'a ParseSess,
-    path: &Path,
-) -> Result<Parser<'a>, Vec<Diagnostic>> {
-    let file = try_file_to_source_file(sess, path, None).map_err(|db| vec![db])?;
-    maybe_source_file_to_parser(sess, file)
-}
-
 /// Given a `source_file` and config, returns a parser.
 fn source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Parser<'_> {
     panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file))
@@ -146,12 +136,6 @@
     Ok(parser)
 }
 
-// Must preserve old name for now, because `quote!` from the *existing*
-// compiler expands into it.
-pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser<'_> {
-    stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS)
-}
-
 // Base abstractions
 
 /// Given a session and a path and an optional span (for error reporting),
@@ -264,29 +248,32 @@
     // As a result, some AST nodes are annotated with the token stream they
     // came from. Here we attempt to extract these lossless token streams
     // before we fall back to the stringification.
+
+    let convert_tokens = |tokens: Option<LazyTokenStream>| tokens.map(|t| t.into_token_stream());
+
     let tokens = match *nt {
         Nonterminal::NtItem(ref item) => {
             prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
         }
-        Nonterminal::NtBlock(ref block) => block.tokens.clone(),
+        Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.clone()),
         Nonterminal::NtStmt(ref stmt) => {
             // FIXME: We currently only collect tokens for `:stmt`
             // matchers in `macro_rules!` macros. When we start collecting
             // tokens for attributes on statements, we will need to prepend
             // attributes here
-            stmt.tokens.clone()
+            convert_tokens(stmt.tokens.clone())
         }
-        Nonterminal::NtPat(ref pat) => pat.tokens.clone(),
-        Nonterminal::NtTy(ref ty) => ty.tokens.clone(),
+        Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.clone()),
+        Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.clone()),
         Nonterminal::NtIdent(ident, is_raw) => {
             Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into())
         }
         Nonterminal::NtLifetime(ident) => {
             Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into())
         }
-        Nonterminal::NtMeta(ref attr) => attr.tokens.clone(),
-        Nonterminal::NtPath(ref path) => path.tokens.clone(),
-        Nonterminal::NtVis(ref vis) => vis.tokens.clone(),
+        Nonterminal::NtMeta(ref attr) => convert_tokens(attr.tokens.clone()),
+        Nonterminal::NtPath(ref path) => convert_tokens(path.tokens.clone()),
+        Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.clone()),
         Nonterminal::NtTT(ref tt) => Some(tt.clone().into()),
         Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => {
             if expr.tokens.is_none() {
@@ -297,7 +284,11 @@
     };
 
     // FIXME(#43081): Avoid this pretty-print + reparse hack
-    let source = pprust::nonterminal_to_string(nt);
+    // Pretty-print the AST struct without inserting any parenthesis
+    // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`).
+    // The resulting stream may have incorrect precedence, but it's only
+    // ever used for a comparison against the capture tokenstream.
+    let source = pprust::nonterminal_to_string_no_extra_parens(nt);
     let filename = FileName::macro_expansion_source_code(&source);
     let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span));
 
@@ -325,15 +316,43 @@
     // modifications, including adding/removing typically non-semantic
     // tokens such as extra braces and commas, don't happen.
     if let Some(tokens) = tokens {
-        if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess) {
+        // Compare with a non-relaxed delim match to start.
+        if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) {
             return tokens;
         }
+
+        // The check failed. This time, we pretty-print the AST struct with parenthesis
+        // inserted to preserve precedence. This may cause `None`-delimiters in the captured
+        // token stream to match up with inserted parenthesis in the reparsed stream.
+        let source_with_parens = pprust::nonterminal_to_string(nt);
+        let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens);
+        let reparsed_tokens_with_parens = parse_stream_from_source_str(
+            filename_with_parens,
+            source_with_parens,
+            sess,
+            Some(span),
+        );
+
+        // Compare with a relaxed delim match - we want inserted parenthesis in the
+        // reparsed stream to match `None`-delimiters in the original stream.
+        if tokenstream_probably_equal_for_proc_macro(
+            &tokens,
+            &reparsed_tokens_with_parens,
+            sess,
+            true,
+        ) {
+            return tokens;
+        }
+
         info!(
             "cached tokens found, but they're not \"probably equal\", \
                 going with stringified version"
         );
-        info!("cached tokens: {:?}", tokens);
-        info!("reparsed tokens: {:?}", reparsed_tokens);
+        info!("cached   tokens: {}", pprust::tts_to_string(&tokens));
+        info!("reparsed tokens: {}", pprust::tts_to_string(&reparsed_tokens_with_parens));
+
+        info!("cached   tokens debug: {:?}", tokens);
+        info!("reparsed tokens debug: {:?}", reparsed_tokens_with_parens);
     }
     reparsed_tokens
 }
@@ -347,6 +366,7 @@
     tokens: &TokenStream,
     reparsed_tokens: &TokenStream,
     sess: &ParseSess,
+    relaxed_delim_match: bool,
 ) -> bool {
     // When checking for `probably_eq`, we ignore certain tokens that aren't
     // preserved in the AST. Because they are not preserved, the pretty
@@ -435,33 +455,46 @@
         token_trees.into_iter()
     }
 
-    let expand_nt = |tree: TokenTree| {
-        if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree {
-            // When checking tokenstreams for 'probable equality', we are comparing
-            // a captured (from parsing) `TokenStream` to a reparsed tokenstream.
-            // The reparsed Tokenstream will never have `None`-delimited groups,
-            // since they are only ever inserted as a result of macro expansion.
-            // Therefore, inserting a `None`-delimtied group here (when we
-            // convert a nested `Nonterminal` to a tokenstream) would cause
-            // a mismatch with the reparsed tokenstream.
-            //
-            // Note that we currently do not handle the case where the
-            // reparsed stream has a `Parenthesis`-delimited group
-            // inserted. This will cause a spurious mismatch:
-            // issue #75734 tracks resolving this.
-            nt_to_tokenstream(nt, sess, *span).into_trees()
-        } else {
-            TokenStream::new(vec![(tree, Spacing::Alone)]).into_trees()
-        }
-    };
+    fn expand_token(tree: TokenTree, sess: &ParseSess) -> impl Iterator<Item = TokenTree> {
+        // When checking tokenstreams for 'probable equality', we are comparing
+        // a captured (from parsing) `TokenStream` to a reparsed tokenstream.
+        // The reparsed Tokenstream will never have `None`-delimited groups,
+        // since they are only ever inserted as a result of macro expansion.
+        // Therefore, inserting a `None`-delimtied group here (when we
+        // convert a nested `Nonterminal` to a tokenstream) would cause
+        // a mismatch with the reparsed tokenstream.
+        //
+        // Note that we currently do not handle the case where the
+        // reparsed stream has a `Parenthesis`-delimited group
+        // inserted. This will cause a spurious mismatch:
+        // issue #75734 tracks resolving this.
+
+        let expanded: SmallVec<[_; 1]> =
+            if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree {
+                nt_to_tokenstream(nt, sess, *span)
+                    .into_trees()
+                    .flat_map(|t| expand_token(t, sess))
+                    .collect()
+            } else {
+                // Filter before and after breaking tokens,
+                // since we may want to ignore both glued and unglued tokens.
+                std::iter::once(tree)
+                    .filter(semantic_tree)
+                    .flat_map(break_tokens)
+                    .filter(semantic_tree)
+                    .collect()
+            };
+        expanded.into_iter()
+    }
 
     // Break tokens after we expand any nonterminals, so that we break tokens
     // that are produced as a result of nonterminal expansion.
-    let tokens = tokens.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
-    let reparsed_tokens =
-        reparsed_tokens.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
+    let tokens = tokens.trees().flat_map(|t| expand_token(t, sess));
+    let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess));
 
-    tokens.eq_by(reparsed_tokens, |t, rt| tokentree_probably_equal_for_proc_macro(&t, &rt, sess))
+    tokens.eq_by(reparsed_tokens, |t, rt| {
+        tokentree_probably_equal_for_proc_macro(&t, &rt, sess, relaxed_delim_match)
+    })
 }
 
 // See comments in `Nonterminal::to_tokenstream` for why we care about
@@ -473,6 +506,7 @@
     token: &TokenTree,
     reparsed_token: &TokenTree,
     sess: &ParseSess,
+    relaxed_delim_match: bool,
 ) -> bool {
     match (token, reparsed_token) {
         (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => {
@@ -481,9 +515,33 @@
         (
             TokenTree::Delimited(_, delim, tokens),
             TokenTree::Delimited(_, reparsed_delim, reparsed_tokens),
-        ) => {
-            delim == reparsed_delim
-                && tokenstream_probably_equal_for_proc_macro(tokens, reparsed_tokens, sess)
+        ) if delim == reparsed_delim => tokenstream_probably_equal_for_proc_macro(
+            tokens,
+            reparsed_tokens,
+            sess,
+            relaxed_delim_match,
+        ),
+        (TokenTree::Delimited(_, DelimToken::NoDelim, tokens), reparsed_token) => {
+            if relaxed_delim_match {
+                if let TokenTree::Delimited(_, DelimToken::Paren, reparsed_tokens) = reparsed_token
+                {
+                    if tokenstream_probably_equal_for_proc_macro(
+                        tokens,
+                        reparsed_tokens,
+                        sess,
+                        relaxed_delim_match,
+                    ) {
+                        return true;
+                    }
+                }
+            }
+            tokens.len() == 1
+                && tokentree_probably_equal_for_proc_macro(
+                    &tokens.trees().next().unwrap(),
+                    reparsed_token,
+                    sess,
+                    relaxed_delim_match,
+                )
         }
         _ => false,
     }
@@ -547,10 +605,10 @@
 fn prepend_attrs(
     sess: &ParseSess,
     attrs: &[ast::Attribute],
-    tokens: Option<&tokenstream::TokenStream>,
+    tokens: Option<&tokenstream::LazyTokenStream>,
     span: rustc_span::Span,
 ) -> Option<tokenstream::TokenStream> {
-    let tokens = tokens?;
+    let tokens = tokens?.clone().into_token_stream();
     if attrs.is_empty() {
         return Some(tokens.clone());
     }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 98f9409..7343964 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -4,7 +4,7 @@
 use rustc_ast::token::{self, Nonterminal};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{error_code, PResult};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 use tracing::debug;
 
@@ -302,3 +302,16 @@
         Err(self.struct_span_err(self.token.span, &msg))
     }
 }
+
+pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
+    attrs.iter().any(|attr| {
+        if let Some(ident) = attr.ident() {
+            ident.name == sym::derive
+            // This might apply a custom attribute/derive
+            || ident.name == sym::cfg_attr
+            || !rustc_feature::is_builtin_attr_name(ident.name)
+        } else {
+            true
+        }
+    })
+}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 9ab13db..1ea01d9 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -5,8 +5,9 @@
 use rustc_ast::token::{self, Lit, LitKind, TokenKind};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{
-    self as ast, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, BlockCheckMode, Expr,
-    ExprKind, Item, ItemKind, Mutability, Param, Pat, PatKind, PathSegment, QSelf, Ty, TyKind,
+    self as ast, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr,
+    ExprKind, Item, ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty,
+    TyKind,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -119,6 +120,28 @@
     No,
 }
 
+#[derive(Clone, Copy)]
+pub enum AttemptLocalParseRecovery {
+    Yes,
+    No,
+}
+
+impl AttemptLocalParseRecovery {
+    pub fn yes(&self) -> bool {
+        match self {
+            AttemptLocalParseRecovery::Yes => true,
+            AttemptLocalParseRecovery::No => false,
+        }
+    }
+
+    pub fn no(&self) -> bool {
+        match self {
+            AttemptLocalParseRecovery::Yes => false,
+            AttemptLocalParseRecovery::No => true,
+        }
+    }
+}
+
 impl<'a> Parser<'a> {
     pub(super) fn span_fatal_err<S: Into<MultiSpan>>(
         &self,
@@ -321,6 +344,66 @@
         }
     }
 
+    pub fn maybe_suggest_struct_literal(
+        &mut self,
+        lo: Span,
+        s: BlockCheckMode,
+    ) -> Option<PResult<'a, P<Block>>> {
+        if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
+            // We might be having a struct literal where people forgot to include the path:
+            // fn foo() -> Foo {
+            //     field: value,
+            // }
+            let mut snapshot = self.clone();
+            let path =
+                Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
+            let struct_expr = snapshot.parse_struct_expr(path, AttrVec::new(), false);
+            let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
+            return Some(match (struct_expr, block_tail) {
+                (Ok(expr), Err(mut err)) => {
+                    // We have encountered the following:
+                    // fn foo() -> Foo {
+                    //     field: value,
+                    // }
+                    // Suggest:
+                    // fn foo() -> Foo { Path {
+                    //     field: value,
+                    // } }
+                    err.delay_as_bug();
+                    self.struct_span_err(expr.span, "struct literal body without path")
+                        .multipart_suggestion(
+                            "you might have forgotten to add the struct literal inside the block",
+                            vec![
+                                (expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()),
+                                (expr.span.shrink_to_hi(), " }".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
+                    *self = snapshot;
+                    Ok(self.mk_block(
+                        vec![self.mk_stmt_err(expr.span)],
+                        s,
+                        lo.to(self.prev_token.span),
+                    ))
+                }
+                (Err(mut err), Ok(tail)) => {
+                    // We have a block tail that contains a somehow valid type ascription expr.
+                    err.cancel();
+                    Ok(tail)
+                }
+                (Err(mut snapshot_err), Err(err)) => {
+                    // We don't know what went wrong, emit the normal error.
+                    snapshot_err.cancel();
+                    self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                    Err(err)
+                }
+                (Ok(_), Ok(tail)) => Ok(tail),
+            });
+        }
+        None
+    }
+
     pub fn maybe_annotate_with_ascription(
         &mut self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 69d13b5..78c9542 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -6,6 +6,7 @@
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::tokenstream::Spacing;
 use rustc_ast::util::classify;
 use rustc_ast::util::literal::LitError;
 use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
@@ -16,8 +17,8 @@
 use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{BytePos, Pos};
 use std::mem;
-use tracing::debug;
 
 /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
 /// dropped into the token stream, which happens while parsing the result of
@@ -245,11 +246,7 @@
                 this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed)
             })?;
 
-            // Make sure that the span of the parent node is larger than the span of lhs and rhs,
-            // including the attributes.
-            let lhs_span =
-                lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span);
-            let span = lhs_span.to(rhs.span);
+            let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
             lhs = match op {
                 AssocOp::Add
                 | AssocOp::Subtract
@@ -410,7 +407,7 @@
             None
         };
         let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
-        let span = lhs.span.to(rhs_span);
+        let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
         let limits =
             if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
         Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits)?, AttrVec::new()))
@@ -462,7 +459,7 @@
     /// Parses a prefix-unary-operator expr.
     fn parse_prefix_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
-        self.maybe_collect_tokens(!attrs.is_empty(), |this| {
+        self.maybe_collect_tokens(super::attr::maybe_needs_tokens(&attrs), |this| {
             let lo = this.token.span;
             // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
             let (hi, ex) = match this.token.uninterpolate().kind {
@@ -570,7 +567,11 @@
         expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
     ) -> PResult<'a, P<Expr>> {
         let mk_expr = |this: &mut Self, rhs: P<Ty>| {
-            this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), AttrVec::new())
+            this.mk_expr(
+                this.mk_expr_sp(&lhs, lhs_span, rhs.span),
+                expr_kind(lhs, rhs),
+                AttrVec::new(),
+            )
         };
 
         // Save the state of the parser before parsing type normally, in case there is a
@@ -839,9 +840,10 @@
         }
         use FloatComponent::*;
 
+        let float_str = float.as_str();
         let mut components = Vec::new();
         let mut ident_like = String::new();
-        for c in float.as_str().chars() {
+        for c in float_str.chars() {
             if c == '_' || c.is_ascii_alphanumeric() {
                 ident_like.push(c);
             } else if matches!(c, '.' | '+' | '-') {
@@ -857,8 +859,13 @@
             components.push(IdentLike(ident_like));
         }
 
-        // FIXME: Make the span more precise.
+        // With proc macros the span can refer to anything, the source may be too short,
+        // or too long, or non-ASCII. It only makes sense to break our span into components
+        // if its underlying text is identical to our float literal.
         let span = self.token.span;
+        let can_take_span_apart =
+            || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
+
         match &*components {
             // 1e2
             [IdentLike(i)] => {
@@ -866,22 +873,43 @@
             }
             // 1.
             [IdentLike(i), Punct('.')] => {
+                let (ident_span, dot_span) = if can_take_span_apart() {
+                    let (span, ident_len) = (span.data(), BytePos::from_usize(i.len()));
+                    let ident_span = span.with_hi(span.lo + ident_len);
+                    let dot_span = span.with_lo(span.lo + ident_len);
+                    (ident_span, dot_span)
+                } else {
+                    (span, span)
+                };
                 assert!(suffix.is_none());
                 let symbol = Symbol::intern(&i);
-                self.token = Token::new(token::Ident(symbol, false), span);
-                let next_token = Token::new(token::Dot, span);
+                self.token = Token::new(token::Ident(symbol, false), ident_span);
+                let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
                 self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token))
             }
             // 1.2 | 1.2e3
             [IdentLike(i1), Punct('.'), IdentLike(i2)] => {
+                let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() {
+                    let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len()));
+                    let ident1_span = span.with_hi(span.lo + ident1_len);
+                    let dot_span = span
+                        .with_lo(span.lo + ident1_len)
+                        .with_hi(span.lo + ident1_len + BytePos(1));
+                    let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1));
+                    (ident1_span, dot_span, ident2_span)
+                } else {
+                    (span, span, span)
+                };
                 let symbol1 = Symbol::intern(&i1);
-                self.token = Token::new(token::Ident(symbol1, false), span);
-                let next_token1 = Token::new(token::Dot, span);
+                self.token = Token::new(token::Ident(symbol1, false), ident1_span);
+                // This needs to be `Spacing::Alone` to prevent regressions.
+                // See issue #76399 and PR #76285 for more details
+                let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
                 let base1 =
                     self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1));
                 let symbol2 = Symbol::intern(&i2);
-                let next_token2 = Token::new(token::Ident(symbol2, false), span);
-                self.bump_with(next_token2); // `.`
+                let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
+                self.bump_with((next_token2, self.token_spacing)); // `.`
                 self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None)
             }
             // 1e+ | 1e- (recovered)
@@ -904,7 +932,7 @@
         base: P<Expr>,
         field: Symbol,
         suffix: Option<Symbol>,
-        next_token: Option<Token>,
+        next_token: Option<(Token, Spacing)>,
     ) -> P<Expr> {
         match next_token {
             Some(next_token) => self.bump_with(next_token),
@@ -1034,6 +1062,8 @@
             })
         } else if self.eat_keyword(kw::Unsafe) {
             self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs)
+        } else if self.check_inline_const(0) {
+            self.parse_const_block(lo.to(self.token.span))
         } else if self.is_do_catch_block() {
             self.recover_do_catch(attrs)
         } else if self.is_try_block() {
@@ -1081,12 +1111,11 @@
 
     fn maybe_collect_tokens(
         &mut self,
-        has_outer_attrs: bool,
+        needs_tokens: bool,
         f: impl FnOnce(&mut Self) -> PResult<'a, P<Expr>>,
     ) -> PResult<'a, P<Expr>> {
-        if has_outer_attrs {
+        if needs_tokens {
             let (mut expr, tokens) = self.collect_tokens(f)?;
-            debug!("maybe_collect_tokens: Collected tokens for {:?} (tokens {:?}", expr, tokens);
             expr.tokens = Some(tokens);
             Ok(expr)
         } else {
@@ -2015,9 +2044,12 @@
     ) -> Option<PResult<'a, P<Expr>>> {
         let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
         if struct_allowed || self.is_certainly_not_a_block() {
-            // This is a struct literal, but we don't can't accept them here.
-            let expr = self.parse_struct_expr(path.clone(), attrs.clone());
+            if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) {
+                return Some(Err(err));
+            }
+            let expr = self.parse_struct_expr(path.clone(), attrs.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
+                // This is a struct literal, but we don't can't accept them here.
                 self.error_struct_lit_not_allowed_here(path.span, expr.span);
             }
             return Some(expr);
@@ -2035,12 +2067,13 @@
             .emit();
     }
 
+    /// Precondition: already parsed the '{'.
     pub(super) fn parse_struct_expr(
         &mut self,
         pth: ast::Path,
         mut attrs: AttrVec,
+        recover: bool,
     ) -> PResult<'a, P<Expr>> {
-        self.bump();
         let mut fields = Vec::new();
         let mut base = None;
         let mut recover_async = false;
@@ -2059,10 +2092,11 @@
                 let exp_span = self.prev_token.span;
                 match self.parse_expr() {
                     Ok(e) => base = Some(e),
-                    Err(mut e) => {
+                    Err(mut e) if recover => {
                         e.emit();
                         self.recover_stmt();
                     }
+                    Err(e) => return Err(e),
                 }
                 self.recover_struct_comma_after_dotdot(exp_span);
                 break;
@@ -2114,6 +2148,9 @@
                             );
                         }
                     }
+                    if !recover {
+                        return Err(e);
+                    }
                     e.emit();
                     self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
                     self.eat(&token::Comma);
@@ -2290,4 +2327,14 @@
     pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> {
         self.mk_expr(span, ExprKind::Err, AttrVec::new())
     }
+
+    /// Create expression span ensuring the span of the parent node
+    /// is larger than the span of lhs and rhs, including the attributes.
+    fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span {
+        lhs.attrs
+            .iter()
+            .find(|a| a.style == AttrStyle::Outer)
+            .map_or(lhs_span, |a| a.span)
+            .to(rhs_span)
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 26ca998..4ad2597 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -116,15 +116,16 @@
             Some(item.into_inner())
         });
 
+        let needs_tokens = super::attr::maybe_needs_tokens(&attrs);
+
         let mut unclosed_delims = vec![];
-        let has_attrs = !attrs.is_empty();
         let parse_item = |this: &mut Self| {
             let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
             unclosed_delims.append(&mut this.unclosed_delims);
             item
         };
 
-        let (mut item, tokens) = if has_attrs {
+        let (mut item, tokens) = if needs_tokens {
             let (item, tokens) = self.collect_tokens(parse_item)?;
             (item, Some(tokens))
         } else {
@@ -1744,7 +1745,7 @@
             }
         };
 
-        let span = lo.to(self.token.span);
+        let span = lo.until(self.token.span);
 
         Ok(Param {
             attrs: attrs.into(),
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 7340c57..8ff9745 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -10,17 +10,21 @@
 mod ty;
 
 use crate::lexer::UnmatchedBrace;
+pub use diagnostics::AttemptLocalParseRecovery;
 use diagnostics::Error;
 pub use path::PathStyle;
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, DelimToken, Token, TokenKind};
-use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
+use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, LazyTokenStreamInner, Spacing};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe};
-use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
+use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe};
+use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit};
+use rustc_ast::{Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
+use rustc_errors::PResult;
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError};
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -83,10 +87,14 @@
     pub sess: &'a ParseSess,
     /// The current token.
     pub token: Token,
+    /// The spacing for the current token
+    pub token_spacing: Spacing,
     /// The previous token.
     pub prev_token: Token,
     restrictions: Restrictions,
     expected_tokens: Vec<TokenType>,
+    // Important: This must only be advanced from `next_tok`
+    // to ensure that `token_cursor.num_next_calls` is updated properly
     token_cursor: TokenCursor,
     desugar_doc_comments: bool,
     /// This field is used to keep track of how many left angle brackets we have seen. This is
@@ -118,8 +126,10 @@
 struct TokenCursor {
     frame: TokenCursorFrame,
     stack: Vec<TokenCursorFrame>,
-    cur_token: Option<TreeAndSpacing>,
-    collecting: Option<Collecting>,
+    desugar_doc_comments: bool,
+    // Counts the number of calls to `next` or `next_desugared`,
+    // depending on whether `desugar_doc_comments` is set.
+    num_next_calls: usize,
 }
 
 #[derive(Clone)]
@@ -131,40 +141,22 @@
     close_delim: bool,
 }
 
-/// Used to track additional state needed by `collect_tokens`
-#[derive(Clone, Debug)]
-struct Collecting {
-    /// Holds the current tokens captured during the most
-    /// recent call to `collect_tokens`
-    buf: Vec<TreeAndSpacing>,
-    /// The depth of the `TokenCursor` stack at the time
-    /// collection was started. When we encounter a `TokenTree::Delimited`,
-    /// we want to record the `TokenTree::Delimited` itself,
-    /// but *not* any of the inner tokens while we are inside
-    /// the new frame (this would cause us to record duplicate tokens).
-    ///
-    /// This `depth` fields tracks stack depth we are recording tokens.
-    /// Only tokens encountered at this depth will be recorded. See
-    /// `TokenCursor::next` for more details.
-    depth: usize,
-}
-
 impl TokenCursorFrame {
-    fn new(span: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self {
+    fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self {
         TokenCursorFrame {
             delim,
             span,
             open_delim: delim == token::NoDelim,
-            tree_cursor: tts.clone().into_trees(),
+            tree_cursor: tts.into_trees(),
             close_delim: delim == token::NoDelim,
         }
     }
 }
 
 impl TokenCursor {
-    fn next(&mut self) -> Token {
+    fn next(&mut self) -> (Token, Spacing) {
         loop {
-            let tree = if !self.frame.open_delim {
+            let (tree, spacing) = if !self.frame.open_delim {
                 self.frame.open_delim = true;
                 TokenTree::open_tt(self.frame.span, self.frame.delim).into()
             } else if let Some(tree) = self.frame.tree_cursor.next_with_spacing() {
@@ -176,40 +168,24 @@
                 self.frame = frame;
                 continue;
             } else {
-                return Token::new(token::Eof, DUMMY_SP);
+                (TokenTree::Token(Token::new(token::Eof, DUMMY_SP)), Spacing::Alone)
             };
 
-            // Don't set an open delimiter as our current token - we want
-            // to leave it as the full `TokenTree::Delimited` from the previous
-            // iteration of this loop
-            if !matches!(tree.0, TokenTree::Token(Token { kind: TokenKind::OpenDelim(_), .. })) {
-                self.cur_token = Some(tree.clone());
-            }
-
-            if let Some(collecting) = &mut self.collecting {
-                if collecting.depth == self.stack.len() {
-                    debug!(
-                        "TokenCursor::next():  collected {:?} at depth {:?}",
-                        tree,
-                        self.stack.len()
-                    );
-                    collecting.buf.push(tree.clone())
+            match tree {
+                TokenTree::Token(token) => {
+                    return (token, spacing);
                 }
-            }
-
-            match tree.0 {
-                TokenTree::Token(token) => return token,
                 TokenTree::Delimited(sp, delim, tts) => {
-                    let frame = TokenCursorFrame::new(sp, delim, &tts);
+                    let frame = TokenCursorFrame::new(sp, delim, tts);
                     self.stack.push(mem::replace(&mut self.frame, frame));
                 }
             }
         }
     }
 
-    fn next_desugared(&mut self) -> Token {
+    fn next_desugared(&mut self) -> (Token, Spacing) {
         let (data, attr_style, sp) = match self.next() {
-            Token { kind: token::DocComment(_, attr_style, data), span } => {
+            (Token { kind: token::DocComment(_, attr_style, data), span }, _) => {
                 (data, attr_style, span)
             }
             tok => return tok,
@@ -247,7 +223,7 @@
             TokenCursorFrame::new(
                 delim_span,
                 token::NoDelim,
-                &if attr_style == AttrStyle::Inner {
+                if attr_style == AttrStyle::Inner {
                     [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
                         .iter()
                         .cloned()
@@ -349,14 +325,15 @@
         let mut parser = Parser {
             sess,
             token: Token::dummy(),
+            token_spacing: Spacing::Alone,
             prev_token: Token::dummy(),
             restrictions: Restrictions::empty(),
             expected_tokens: Vec::new(),
             token_cursor: TokenCursor {
-                frame: TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, &tokens),
+                frame: TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens),
                 stack: Vec::new(),
-                cur_token: None,
-                collecting: None,
+                num_next_calls: 0,
+                desugar_doc_comments,
             },
             desugar_doc_comments,
             unmatched_angle_bracket_count: 0,
@@ -373,20 +350,21 @@
         parser
     }
 
-    fn next_tok(&mut self, fallback_span: Span) -> Token {
-        let mut next = if self.desugar_doc_comments {
+    fn next_tok(&mut self, fallback_span: Span) -> (Token, Spacing) {
+        let (mut next, spacing) = if self.desugar_doc_comments {
             self.token_cursor.next_desugared()
         } else {
             self.token_cursor.next()
         };
+        self.token_cursor.num_next_calls += 1;
         if next.span.is_dummy() {
             // Tweak the location for better diagnostics, but keep syntactic context intact.
             next.span = fallback_span.with_ctxt(next.span.ctxt());
         }
-        next
+        (next, spacing)
     }
 
-    crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
+    pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
         match self.expect_one_of(&[], &[]) {
             Err(e) => Err(e),
             // We can get `Ok(true)` from `recover_closing_delimiter`
@@ -544,6 +522,15 @@
         self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const)
     }
 
+    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(ref nt) => matches!(**nt, token::NtBlock(..)),
+                token::OpenDelim(DelimToken::Brace) => true,
+                _ => false,
+            })
+    }
+
     /// Checks to see if the next token is either `+` or `+=`.
     /// Otherwise returns `false`.
     fn check_plus(&mut self) -> bool {
@@ -566,7 +553,9 @@
                 let first_span = self.sess.source_map().start_point(self.token.span);
                 let second_span = self.token.span.with_lo(first_span.hi());
                 self.token = Token::new(first, first_span);
-                self.bump_with(Token::new(second, second_span));
+                // Use the spacing of the glued token as the spacing
+                // of the unglued second token.
+                self.bump_with((Token::new(second, second_span), self.token_spacing));
                 true
             }
             _ => {
@@ -798,7 +787,7 @@
     }
 
     /// Advance the parser by one token using provided token as the next one.
-    fn bump_with(&mut self, next_token: Token) {
+    fn bump_with(&mut self, (next_token, next_spacing): (Token, Spacing)) {
         // Bumping after EOF is a bad sign, usually an infinite loop.
         if self.prev_token.kind == TokenKind::Eof {
             let msg = "attempted to bump the parser past EOF (may be stuck in a loop)";
@@ -807,6 +796,7 @@
 
         // Update the current and previous tokens.
         self.prev_token = mem::replace(&mut self.token, next_token);
+        self.token_spacing = next_spacing;
 
         // Diagnostics.
         self.expected_tokens.clear();
@@ -826,15 +816,15 @@
         }
 
         let frame = &self.token_cursor.frame;
-        looker(&match frame.tree_cursor.look_ahead(dist - 1) {
+        match frame.tree_cursor.look_ahead(dist - 1) {
             Some(tree) => match tree {
-                TokenTree::Token(token) => token,
+                TokenTree::Token(token) => looker(token),
                 TokenTree::Delimited(dspan, delim, _) => {
-                    Token::new(token::OpenDelim(delim), dspan.open)
+                    looker(&Token::new(token::OpenDelim(*delim), dspan.open))
                 }
             },
-            None => Token::new(token::CloseDelim(frame.delim), frame.span.close),
-        })
+            None => looker(&Token::new(token::CloseDelim(frame.delim), frame.span.close)),
+        }
     }
 
     /// Returns whether any of the given keywords are `dist` tokens ahead of the current one.
@@ -863,13 +853,28 @@
 
     /// Parses constness: `const` or nothing.
     fn parse_constness(&mut self) -> Const {
-        if self.eat_keyword(kw::Const) {
+        // Avoid const blocks to be parsed as const items
+        if self.look_ahead(1, |t| t != &token::OpenDelim(DelimToken::Brace))
+            && self.eat_keyword(kw::Const)
+        {
             Const::Yes(self.prev_token.uninterpolated_span())
         } else {
             Const::No
         }
     }
 
+    /// Parses inline const expressions.
+    fn parse_const_block(&mut self, span: Span) -> PResult<'a, P<Expr>> {
+        self.sess.gated_spans.gate(sym::inline_const, span);
+        self.eat_keyword(kw::Const);
+        let blk = self.parse_block()?;
+        let anon_const = AnonConst {
+            id: DUMMY_NODE_ID,
+            value: self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()),
+        };
+        Ok(self.mk_expr(span, ExprKind::ConstBlock(anon_const), AttrVec::new()))
+    }
+
     /// Parses mutability (`mut` or nothing).
     fn parse_mutability(&mut self) -> Mutability {
         if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not }
@@ -962,13 +967,27 @@
     pub(crate) fn parse_token_tree(&mut self) -> TokenTree {
         match self.token.kind {
             token::OpenDelim(..) => {
-                let frame = mem::replace(
-                    &mut self.token_cursor.frame,
-                    self.token_cursor.stack.pop().unwrap(),
-                );
-                self.token = Token::new(TokenKind::CloseDelim(frame.delim), frame.span.close);
+                let depth = self.token_cursor.stack.len();
+
+                // We keep advancing the token cursor until we hit
+                // the matching `CloseDelim` token.
+                while !(depth == self.token_cursor.stack.len()
+                    && matches!(self.token.kind, token::CloseDelim(_)))
+                {
+                    // Advance one token at a time, so `TokenCursor::next()`
+                    // can capture these tokens if necessary.
+                    self.bump();
+                }
+                // We are still inside the frame corresponding
+                // to the delimited stream we captured, so grab
+                // the tokens from this frame.
+                let frame = &self.token_cursor.frame;
+                let stream = frame.tree_cursor.stream.clone();
+                let span = frame.span;
+                let delim = frame.delim;
+                // Consume close delimiter
                 self.bump();
-                TokenTree::Delimited(frame.span, frame.delim, frame.tree_cursor.stream)
+                TokenTree::Delimited(span, delim, stream)
             }
             token::CloseDelim(_) | token::Eof => unreachable!(),
             _ => {
@@ -1176,79 +1195,45 @@
     pub fn collect_tokens<R>(
         &mut self,
         f: impl FnOnce(&mut Self) -> PResult<'a, R>,
-    ) -> PResult<'a, (R, TokenStream)> {
-        // Record all tokens we parse when parsing this item.
-        let tokens: Vec<TreeAndSpacing> = self.token_cursor.cur_token.clone().into_iter().collect();
-        debug!("collect_tokens: starting with {:?}", tokens);
+    ) -> PResult<'a, (R, LazyTokenStream)> {
+        let start_token = (self.token.clone(), self.token_spacing);
+        let mut cursor_snapshot = self.token_cursor.clone();
 
-        // We need special handling for the case where `collect_tokens` is called
-        // on an opening delimeter (e.g. '('). At this point, we have already pushed
-        // a new frame - however, we want to record the original `TokenTree::Delimited`,
-        // for consistency with the case where we start recording one token earlier.
-        // See `TokenCursor::next` to see how `cur_token` is set up.
-        let prev_depth =
-            if matches!(self.token_cursor.cur_token, Some((TokenTree::Delimited(..), _))) {
-                if self.token_cursor.stack.is_empty() {
-                    // There is nothing below us in the stack that
-                    // the function could consume, so the only thing it can legally
-                    // capture is the entire contents of the current frame.
-                    return Ok((f(self)?, TokenStream::new(tokens)));
-                }
-                // We have already recorded the full `TokenTree::Delimited` when we created
-                // our `tokens` vector at the start of this function. We are now inside
-                // a new frame corresponding to the `TokenTree::Delimited` we already recoreded.
-                // We don't want to record any of the tokens inside this frame, since they
-                // will be duplicates of the tokens nested inside the `TokenTree::Delimited`.
-                // Therefore, we set our recording depth to the *previous* frame. This allows
-                // us to record a sequence like: `(foo).bar()`: the `(foo)` will be recored
-                // as our initial `cur_token`, while the `.bar()` will be recored after we
-                // pop the `(foo)` frame.
-                self.token_cursor.stack.len() - 1
-            } else {
-                self.token_cursor.stack.len()
-            };
-        let prev_collecting =
-            self.token_cursor.collecting.replace(Collecting { buf: tokens, depth: prev_depth });
+        let ret = f(self)?;
 
-        let ret = f(self);
+        let new_calls = self.token_cursor.num_next_calls;
+        let num_calls = new_calls - cursor_snapshot.num_next_calls;
+        let desugar_doc_comments = self.desugar_doc_comments;
 
-        let mut collected_tokens = if let Some(collecting) = self.token_cursor.collecting.take() {
-            collecting.buf
-        } else {
-            let msg = "our vector went away?";
-            debug!("collect_tokens: {}", msg);
-            self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg);
-            // This can happen due to a bad interaction of two unrelated recovery mechanisms
-            // with mismatched delimiters *and* recovery lookahead on the likely typo
-            // `pub ident(` (#62895, different but similar to the case above).
-            return Ok((ret?, TokenStream::default()));
+        // Produces a `TokenStream` on-demand. Using `cursor_snapshot`
+        // and `num_calls`, we can reconstruct the `TokenStream` seen
+        // by the callback. This allows us to avoid producing a `TokenStream`
+        // if it is never needed - for example, a captured `macro_rules!`
+        // argument that is never passed to a proc macro.
+        //
+        // This also makes `Parser` very cheap to clone, since
+        // there is no intermediate collection buffer to clone.
+        let lazy_cb = move || {
+            // The token produced by the final call to `next` or `next_desugared`
+            // was not actually consumed by the callback. The combination
+            // of chaining the initial token and using `take` produces the desired
+            // result - we produce an empty `TokenStream` if no calls were made,
+            // and omit the final token otherwise.
+            let tokens = std::iter::once(start_token)
+                .chain((0..num_calls).map(|_| {
+                    if desugar_doc_comments {
+                        cursor_snapshot.next_desugared()
+                    } else {
+                        cursor_snapshot.next()
+                    }
+                }))
+                .take(num_calls);
+
+            make_token_stream(tokens)
         };
+        let stream = LazyTokenStream::new(LazyTokenStreamInner::Lazy(Box::new(lazy_cb)));
 
-        debug!("collect_tokens: got raw tokens {:?}", collected_tokens);
-
-        // If we're not at EOF our current token wasn't actually consumed by
-        // `f`, but it'll still be in our list that we pulled out. In that case
-        // put it back.
-        let extra_token = if self.token != token::Eof { collected_tokens.pop() } else { None };
-
-        if let Some(mut collecting) = prev_collecting {
-            // If we were previously collecting at the same depth,
-            // then the previous call to `collect_tokens` needs to see
-            // the tokens we just recorded.
-            //
-            // If we were previously recording at an lower `depth`,
-            // then the previous `collect_tokens` call already recorded
-            // this entire frame in the form of a `TokenTree::Delimited`,
-            // so there is nothing else for us to do.
-            if collecting.depth == prev_depth {
-                collecting.buf.extend(collected_tokens.iter().cloned());
-                collecting.buf.extend(extra_token);
-                debug!("collect_tokens: updating previous buf to {:?}", collecting);
-            }
-            self.token_cursor.collecting = Some(collecting)
-        }
-
-        Ok((ret?, TokenStream::new(collected_tokens)))
+        Ok((ret, stream))
     }
 
     /// `::{` or `::*`
@@ -1297,3 +1282,41 @@
         }
     }
 }
+
+/// Converts a flattened iterator of tokens (including open and close delimiter tokens)
+/// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair
+/// of open and close delims.
+fn make_token_stream(tokens: impl Iterator<Item = (Token, Spacing)>) -> TokenStream {
+    #[derive(Debug)]
+    struct FrameData {
+        open: Span,
+        inner: Vec<(TokenTree, Spacing)>,
+    }
+    let mut stack = vec![FrameData { open: DUMMY_SP, inner: vec![] }];
+    for (token, spacing) in tokens {
+        match token {
+            Token { kind: TokenKind::OpenDelim(_), span } => {
+                stack.push(FrameData { open: span, inner: vec![] });
+            }
+            Token { kind: TokenKind::CloseDelim(delim), span } => {
+                let frame_data = stack.pop().expect("Token stack was empty!");
+                let dspan = DelimSpan::from_pair(frame_data.open, span);
+                let stream = TokenStream::new(frame_data.inner);
+                let delimited = TokenTree::Delimited(dspan, delim, stream);
+                stack
+                    .last_mut()
+                    .unwrap_or_else(|| panic!("Bottom token frame is missing for tokens!"))
+                    .inner
+                    .push((delimited, Spacing::Alone));
+            }
+            token => stack
+                .last_mut()
+                .expect("Bottom token frame is missing!")
+                .inner
+                .push((TokenTree::Token(token), spacing)),
+        }
+    }
+    let final_buf = stack.pop().expect("Missing final buf!");
+    assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
+    TokenStream::new(final_buf.inner)
+}
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 2c0133a..27fe75a 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -313,6 +313,15 @@
             let pat = self.parse_pat_with_range_pat(false, None)?;
             self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span));
             PatKind::Box(pat)
+        } else if self.check_inline_const(0) {
+            // Parse `const pat`
+            let const_expr = self.parse_const_block(lo.to(self.token.span))?;
+
+            if let Some(re) = self.parse_range_end() {
+                self.parse_pat_range_begin_with(const_expr, re)?
+            } else {
+                PatKind::Lit(const_expr)
+            }
         } else if self.can_be_ident_pat() {
             // Parse `ident @ pat`
             // This can give false positives and parse nullary enums,
@@ -714,16 +723,19 @@
 
     /// Is the token `dist` away from the current suitable as the start of a range patterns end?
     fn is_pat_range_end_start(&self, dist: usize) -> bool {
-        self.look_ahead(dist, |t| {
-            t.is_path_start() // e.g. `MY_CONST`;
+        self.check_inline_const(dist)
+            || self.look_ahead(dist, |t| {
+                t.is_path_start() // e.g. `MY_CONST`;
                 || t.kind == token::Dot // e.g. `.5` for recovery;
                 || t.can_begin_literal_maybe_minus() // e.g. `42`.
                 || t.is_whole_expr()
-        })
+            })
     }
 
     fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
-        if self.check_path() {
+        if self.check_inline_const(0) {
+            self.parse_const_block(self.token.span)
+        } else if self.check_path() {
             let lo = self.token.span;
             let (qself, path) = if self.eat_lt() {
                 // Parse a qualified path
@@ -795,6 +807,7 @@
         }
         self.bump();
         let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| {
+            e.span_label(path.span, "while parsing the fields for this pattern");
             e.emit();
             self.recover_stmt();
             (vec![], true)
@@ -844,7 +857,7 @@
 
             // check that a comma comes after every field
             if !ate_comma {
-                let err = self.struct_span_err(self.prev_token.span, "expected `,`");
+                let err = self.struct_span_err(self.token.span, "expected `,`");
                 if let Some(mut delayed) = delayed_err {
                     delayed.emit();
                 }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index fd1c6b2..131ff1a 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -1,5 +1,5 @@
 use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
-use super::diagnostics::Error;
+use super::diagnostics::{AttemptLocalParseRecovery, Error};
 use super::expr::LhsExpr;
 use super::pat::GateOr;
 use super::path::PathStyle;
@@ -79,8 +79,8 @@
             return self.parse_stmt_mac(lo, attrs.into(), path);
         }
 
-        let expr = if self.check(&token::OpenDelim(token::Brace)) {
-            self.parse_struct_expr(path, AttrVec::new())?
+        let expr = if self.eat(&token::OpenDelim(token::Brace)) {
+            self.parse_struct_expr(path, AttrVec::new(), true)?
         } else {
             let hi = self.prev_token.span;
             self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
@@ -321,25 +321,37 @@
             return self.error_block_no_opening_brace();
         }
 
-        Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, blk_mode)?))
+        let attrs = self.parse_inner_attributes()?;
+        let tail = if let Some(tail) = self.maybe_suggest_struct_literal(lo, blk_mode) {
+            tail?
+        } else {
+            self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?
+        };
+        Ok((attrs, tail))
     }
 
     /// Parses the rest of a block expression or function body.
     /// Precondition: already parsed the '{'.
-    fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> {
+    crate fn parse_block_tail(
+        &mut self,
+        lo: Span,
+        s: BlockCheckMode,
+        recover: AttemptLocalParseRecovery,
+    ) -> PResult<'a, P<Block>> {
         let mut stmts = vec![];
         while !self.eat(&token::CloseDelim(token::Brace)) {
             if self.token == token::Eof {
                 break;
             }
-            let stmt = match self.parse_full_stmt() {
-                Err(mut err) => {
+            let stmt = match self.parse_full_stmt(recover) {
+                Err(mut err) if recover.yes() => {
                     self.maybe_annotate_with_ascription(&mut err, false);
                     err.emit();
                     self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
                     Some(self.mk_stmt_err(self.token.span))
                 }
                 Ok(stmt) => stmt,
+                Err(err) => return Err(err),
             };
             if let Some(stmt) = stmt {
                 stmts.push(stmt);
@@ -352,7 +364,10 @@
     }
 
     /// Parses a statement, including the trailing semicolon.
-    pub fn parse_full_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
+    pub fn parse_full_stmt(
+        &mut self,
+        recover: AttemptLocalParseRecovery,
+    ) -> PResult<'a, Option<Stmt>> {
         // Skip looking for a trailing semicolon when we have an interpolated statement.
         maybe_whole!(self, NtStmt, |x| Some(x));
 
@@ -391,6 +406,9 @@
                     if let Err(mut e) =
                         self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
                     {
+                        if recover.no() {
+                            return Err(e);
+                        }
                         e.emit();
                         self.recover_stmt();
                     }
@@ -432,7 +450,7 @@
         Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None }
     }
 
-    fn mk_stmt_err(&self, span: Span) -> Stmt {
+    pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt {
         self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span)))
     }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 758b463..cb9c0578 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -8,17 +8,19 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 
-use rustc_ast::{Attribute, NestedMetaItem};
-use rustc_errors::struct_span_err;
+use rustc_ast::{Attribute, LitKind, NestedMetaItem};
+use rustc_errors::{pluralize, struct_span_err};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{self, HirId, Item, ItemKind, TraitItem};
+use rustc_hir::{
+    self, FnSig, ForeignItem, ForeignItemKind, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID,
+};
 use rustc_hir::{MethodKind, Target};
 use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES};
 use rustc_session::parse::feature_err;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::{Span, DUMMY_SP};
 
 pub(crate) fn target_from_impl_item<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -43,6 +45,12 @@
     }
 }
 
+#[derive(Clone, Copy)]
+enum ItemLike<'tcx> {
+    Item(&'tcx Item<'tcx>),
+    ForeignItem(&'tcx ForeignItem<'tcx>),
+}
+
 struct CheckAttrVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
@@ -55,7 +63,7 @@
         attrs: &'hir [Attribute],
         span: &Span,
         target: Target,
-        item: Option<&Item<'_>>,
+        item: Option<ItemLike<'_>>,
     ) {
         let mut is_valid = true;
         for attr in attrs {
@@ -75,6 +83,8 @@
                 self.check_no_link(&attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::export_name) {
                 self.check_export_name(&attr, span, target)
+            } else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) {
+                self.check_rustc_args_required_const(&attr, span, target, item)
             } else {
                 // lint-only checks
                 if self.tcx.sess.check_name(attr, sym::cold) {
@@ -252,23 +262,53 @@
         }
     }
 
+    fn doc_alias_str_error(&self, meta: &NestedMetaItem) {
+        self.tcx
+            .sess
+            .struct_span_err(
+                meta.span(),
+                "doc alias attribute expects a string: #[doc(alias = \"0\")]",
+            )
+            .emit();
+    }
+
     fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool {
         if let Some(mi) = attr.meta() {
             if let Some(list) = mi.meta_item_list() {
                 for meta in list {
                     if meta.has_name(sym::alias) {
-                        if !meta.is_value_str()
-                            || meta
-                                .value_str()
-                                .map(|s| s.to_string())
-                                .unwrap_or_else(String::new)
-                                .is_empty()
+                        if !meta.is_value_str() {
+                            self.doc_alias_str_error(meta);
+                            return false;
+                        }
+                        let doc_alias =
+                            meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
+                        if doc_alias.is_empty() {
+                            self.doc_alias_str_error(meta);
+                            return false;
+                        }
+                        if let Some(c) = doc_alias
+                            .chars()
+                            .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
                         {
                             self.tcx
                                 .sess
                                 .struct_span_err(
                                     meta.span(),
-                                    "doc alias attribute expects a string: #[doc(alias = \"0\")]",
+                                    &format!(
+                                        "{:?} character isn't allowed in `#[doc(alias = \"...\")]`",
+                                        c,
+                                    ),
+                                )
+                                .emit();
+                            return false;
+                        }
+                        if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
+                            self.tcx
+                                .sess
+                                .struct_span_err(
+                                    meta.span(),
+                                    "`#[doc(alias = \"...\")]` cannot start or end with ' '",
                                 )
                                 .emit();
                             return false;
@@ -304,6 +344,18 @@
                                     &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err),
                                 )
                                 .emit();
+                            return false;
+                        }
+                        if CRATE_HIR_ID == hir_id {
+                            self.tcx
+                                .sess
+                                .struct_span_err(
+                                    meta.span(),
+                                    "`#![doc(alias = \"...\")]` isn't allowed as a crate \
+                                     level attribute",
+                                )
+                                .emit();
+                            return false;
                         }
                     }
                 }
@@ -400,6 +452,71 @@
         }
     }
 
+    /// Checks if `#[rustc_args_required_const]` is applied to a function and has a valid argument.
+    fn check_rustc_args_required_const(
+        &self,
+        attr: &Attribute,
+        span: &Span,
+        target: Target,
+        item: Option<ItemLike<'_>>,
+    ) -> bool {
+        if let Target::Fn | Target::Method(..) | Target::ForeignFn = target {
+            let mut invalid_args = vec![];
+            for meta in attr.meta_item_list().expect("no meta item list") {
+                if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
+                    if let Some(ItemLike::Item(Item {
+                        kind: ItemKind::Fn(FnSig { decl, .. }, ..),
+                        ..
+                    }))
+                    | Some(ItemLike::ForeignItem(ForeignItem {
+                        kind: ForeignItemKind::Fn(decl, ..),
+                        ..
+                    })) = item
+                    {
+                        let arg_count = decl.inputs.len() as u128;
+                        if *val >= arg_count {
+                            let span = meta.span();
+                            self.tcx
+                                .sess
+                                .struct_span_err(span, "index exceeds number of arguments")
+                                .span_label(
+                                    span,
+                                    format!(
+                                        "there {} only {} argument{}",
+                                        if arg_count != 1 { "are" } else { "is" },
+                                        arg_count,
+                                        pluralize!(arg_count)
+                                    ),
+                                )
+                                .emit();
+                            return false;
+                        }
+                    } else {
+                        bug!("should be a function item");
+                    }
+                } else {
+                    invalid_args.push(meta.span());
+                }
+            }
+            if !invalid_args.is_empty() {
+                self.tcx
+                    .sess
+                    .struct_span_err(invalid_args, "arguments should be non-negative integers")
+                    .emit();
+                false
+            } else {
+                true
+            }
+        } else {
+            self.tcx
+                .sess
+                .struct_span_err(attr.span, "attribute should be applied to a function")
+                .span_label(*span, "not a function")
+                .emit();
+            false
+        }
+    }
+
     /// Checks if `#[link_section]` is applied to a function or static.
     fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
@@ -448,7 +565,7 @@
         attrs: &'hir [Attribute],
         span: &Span,
         target: Target,
-        item: Option<&Item<'_>>,
+        item: Option<ItemLike<'_>>,
         hir_id: HirId,
     ) {
         // Extract the names of all repr hints, e.g., [foo, bar, align] for:
@@ -571,7 +688,14 @@
         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
         if (int_reprs > 1)
             || (is_simd && is_c)
-            || (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item)))
+            || (int_reprs == 1
+                && is_c
+                && item.map_or(false, |item| {
+                    if let ItemLike::Item(item) = item {
+                        return is_c_like_enum(item);
+                    }
+                    return false;
+                }))
         {
             self.tcx.struct_span_lint_hir(
                 CONFLICTING_REPR_HINTS,
@@ -606,7 +730,13 @@
 
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
         let target = Target::from_item(item);
-        self.check_attributes(item.hir_id, item.attrs, &item.span, target, Some(item));
+        self.check_attributes(
+            item.hir_id,
+            item.attrs,
+            &item.span,
+            target,
+            Some(ItemLike::Item(item)),
+        );
         intravisit::walk_item(self, item)
     }
 
@@ -616,9 +746,15 @@
         intravisit::walk_trait_item(self, trait_item)
     }
 
-    fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem<'tcx>) {
+    fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
         let target = Target::from_foreign_item(f_item);
-        self.check_attributes(f_item.hir_id, &f_item.attrs, &f_item.span, target, None);
+        self.check_attributes(
+            f_item.hir_id,
+            &f_item.attrs,
+            &f_item.span,
+            target,
+            Some(ItemLike::ForeignItem(f_item)),
+        );
         intravisit::walk_foreign_item(self, f_item)
     }
 
@@ -671,9 +807,46 @@
     }
 }
 
+fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
+    const ATTRS_TO_CHECK: &[Symbol] = &[
+        sym::macro_export,
+        sym::repr,
+        sym::path,
+        sym::automatically_derived,
+        sym::start,
+        sym::main,
+    ];
+
+    for attr in attrs {
+        for attr_to_check in ATTRS_TO_CHECK {
+            if tcx.sess.check_name(attr, *attr_to_check) {
+                tcx.sess
+                    .struct_span_err(
+                        attr.span,
+                        &format!(
+                            "`{}` attribute cannot be used at crate level",
+                            attr_to_check.to_ident_string()
+                        ),
+                    )
+                    .emit();
+            }
+        }
+    }
+}
+
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     tcx.hir()
         .visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
+    if module_def_id.is_top_level_module() {
+        CheckAttrVisitor { tcx }.check_attributes(
+            CRATE_HIR_ID,
+            tcx.hir().krate_attrs(),
+            &DUMMY_SP,
+            Target::Mod,
+            None,
+        );
+        check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
+    }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 98ded41..f567dd8 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -458,8 +458,8 @@
         .map
         .iter()
         .filter_map(
-            |(&id, level)| {
-                if level >= &privacy::AccessLevel::Reachable { Some(id) } else { None }
+            |(&id, &level)| {
+                if level >= privacy::AccessLevel::Reachable { Some(id) } else { None }
             },
         )
         .chain(
@@ -547,7 +547,7 @@
         let def_id = self.tcx.hir().local_def_id(id);
         let inherent_impls = self.tcx.inherent_impls(def_id);
         for &impl_did in inherent_impls.iter() {
-            for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
+            for item_did in self.tcx.associated_item_def_ids(impl_did) {
                 if let Some(did) = item_did.as_local() {
                     let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(did);
                     if self.live_symbols.contains(&item_hir_id) {
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 8aa6e79..e87adb37 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -78,29 +78,38 @@
 // Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
 // (with `ast::Item`), so make sure to keep them in sync.
 fn entry_point_type(sess: &Session, item: &Item<'_>, at_root: bool) -> EntryPointType {
-    match item.kind {
-        ItemKind::Fn(..) => {
-            if sess.contains_name(&item.attrs, sym::start) {
-                EntryPointType::Start
-            } else if sess.contains_name(&item.attrs, sym::main) {
-                EntryPointType::MainAttr
-            } else if item.ident.name == sym::main {
-                if at_root {
-                    // This is a top-level function so can be `main`.
-                    EntryPointType::MainNamed
-                } else {
-                    EntryPointType::OtherMain
-                }
-            } else {
-                EntryPointType::None
-            }
+    if sess.contains_name(&item.attrs, sym::start) {
+        EntryPointType::Start
+    } else if sess.contains_name(&item.attrs, sym::main) {
+        EntryPointType::MainAttr
+    } else if item.ident.name == sym::main {
+        if at_root {
+            // This is a top-level function so can be `main`.
+            EntryPointType::MainNamed
+        } else {
+            EntryPointType::OtherMain
         }
-        _ => EntryPointType::None,
+    } else {
+        EntryPointType::None
     }
 }
 
+fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
+    sess.struct_span_err(span, &format!("`{}` attribute can only be used on functions", attr))
+        .emit();
+}
+
 fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
     match entry_point_type(&ctxt.session, item, at_root) {
+        EntryPointType::None => (),
+        _ if !matches!(item.kind, ItemKind::Fn(..)) => {
+            if let Some(attr) = ctxt.session.find_by_name(item.attrs, sym::start) {
+                throw_attr_err(&ctxt.session, attr.span, "start");
+            }
+            if let Some(attr) = ctxt.session.find_by_name(item.attrs, sym::main) {
+                throw_attr_err(&ctxt.session, attr.span, "main");
+            }
+        }
         EntryPointType::MainNamed => {
             if ctxt.main_fn.is_none() {
                 ctxt.main_fn = Some((item.hir_id, item.span));
@@ -137,7 +146,6 @@
                     .emit();
             }
         }
-        EntryPointType::None => (),
     }
 }
 
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 79f1c2b..956be92 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -143,7 +143,7 @@
     ) -> Option<InlineAsmType> {
         // Check the type against the allowed types for inline asm.
         let ty = self.typeck_results.expr_ty_adjusted(expr);
-        let asm_ty_isize = match self.tcx.sess.target.ptr_width {
+        let asm_ty_isize = match self.tcx.sess.target.pointer_width {
             16 => InlineAsmType::I16,
             32 => InlineAsmType::I32,
             64 => InlineAsmType::I64,
@@ -184,7 +184,7 @@
                         Some(InlineAsmType::VecI128(fields.len() as u64))
                     }
                     ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => {
-                        Some(match self.tcx.sess.target.ptr_width {
+                        Some(match self.tcx.sess.target.pointer_width {
                             16 => InlineAsmType::VecI16(fields.len() as u64),
                             32 => InlineAsmType::VecI32(fields.len() as u64),
                             64 => InlineAsmType::VecI64(fields.len() as u64),
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 9eac2f7..7288015 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -62,13 +62,13 @@
 //! - `reader`: the `LiveNode` ID of some node which will read the value
 //!    that `V` holds on entry to `N`. Formally: a node `M` such
 //!    that there exists a path `P` from `N` to `M` where `P` does not
-//!    write `V`. If the `reader` is `INVALID_NODE`, then the current
+//!    write `V`. If the `reader` is `None`, then the current
 //!    value will never be read (the variable is dead, essentially).
 //!
 //! - `writer`: the `LiveNode` ID of some node which will write the
 //!    variable `V` and which is reachable from `N`. Formally: a node `M`
 //!    such that there exists a path `P` from `N` to `M` and `M` writes
-//!    `V`. If the `writer` is `INVALID_NODE`, then there is no writer
+//!    `V`. If the `writer` is `None`, then there is no writer
 //!    of `V` that follows `N`.
 //!
 //! - `used`: a boolean value indicating whether `V` is *used*. We
@@ -90,12 +90,12 @@
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor};
-use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet};
 use rustc_index::vec::IndexVec;
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::lint;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
@@ -114,7 +114,6 @@
 rustc_index::newtype_index! {
     pub struct LiveNode {
         DEBUG_FORMAT = "ln({})",
-        const INVALID_NODE = LiveNode::MAX_AS_U32,
     }
 }
 
@@ -138,40 +137,8 @@
     }
 }
 
-impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
-    type Map = Map<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
-    }
-
-    fn visit_fn(
-        &mut self,
-        fk: FnKind<'tcx>,
-        fd: &'tcx hir::FnDecl<'tcx>,
-        b: hir::BodyId,
-        s: Span,
-        id: HirId,
-    ) {
-        visit_fn(self, fk, fd, b, s, id);
-    }
-
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
-        visit_local(self, l);
-    }
-    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
-        visit_expr(self, ex);
-    }
-    fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
-        visit_arm(self, a);
-    }
-}
-
 fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(
-        module_def_id,
-        &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
-    );
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor());
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -200,12 +167,6 @@
 // variable must not be assigned if there is some successor
 // assignment.  And so forth.
 
-impl LiveNode {
-    fn is_valid(self) -> bool {
-        self != INVALID_NODE
-    }
-}
-
 struct CaptureInfo {
     ln: LiveNode,
     var_hid: HirId,
@@ -227,7 +188,6 @@
 
 struct IrMaps<'tcx> {
     tcx: TyCtxt<'tcx>,
-    body_owner: LocalDefId,
     live_node_map: HirIdMap<LiveNode>,
     variable_map: HirIdMap<Variable>,
     capture_info_map: HirIdMap<Rc<Vec<CaptureInfo>>>,
@@ -236,10 +196,9 @@
 }
 
 impl IrMaps<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, body_owner: LocalDefId) -> IrMaps<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> IrMaps<'tcx> {
         IrMaps {
             tcx,
-            body_owner,
             live_node_map: HirIdMap::default(),
             variable_map: HirIdMap::default(),
             capture_info_map: Default::default(),
@@ -302,44 +261,106 @@
     fn set_captures(&mut self, hir_id: HirId, cs: Vec<CaptureInfo>) {
         self.capture_info_map.insert(hir_id, Rc::new(cs));
     }
-}
 
-fn visit_fn<'tcx>(
-    ir: &mut IrMaps<'tcx>,
-    fk: FnKind<'tcx>,
-    decl: &'tcx hir::FnDecl<'tcx>,
-    body_id: hir::BodyId,
-    sp: Span,
-    id: hir::HirId,
-) {
-    debug!("visit_fn {:?}", id);
-
-    // swap in a new set of IR maps for this function body:
-    let def_id = ir.tcx.hir().local_def_id(id);
-    let mut fn_maps = IrMaps::new(ir.tcx, def_id);
-
-    // Don't run unused pass for #[derive()]
-    if let FnKind::Method(..) = fk {
-        let parent = ir.tcx.hir().get_parent_item(id);
-        if let Some(Node::Item(i)) = ir.tcx.hir().find(parent) {
-            if i.attrs.iter().any(|a| ir.tcx.sess.check_name(a, sym::automatically_derived)) {
-                return;
+    fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
+        // For struct patterns, take note of which fields used shorthand
+        // (`x` rather than `x: x`).
+        let mut shorthand_field_ids = HirIdSet::default();
+        let mut pats = VecDeque::new();
+        pats.push_back(pat);
+        while let Some(pat) = pats.pop_front() {
+            use rustc_hir::PatKind::*;
+            match &pat.kind {
+                Binding(.., inner_pat) => {
+                    pats.extend(inner_pat.iter());
+                }
+                Struct(_, fields, _) => {
+                    let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id);
+                    shorthand_field_ids.extend(ids);
+                }
+                Ref(inner_pat, _) | Box(inner_pat) => {
+                    pats.push_back(inner_pat);
+                }
+                TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => {
+                    pats.extend(inner_pats.iter());
+                }
+                Slice(pre_pats, inner_pat, post_pats) => {
+                    pats.extend(pre_pats.iter());
+                    pats.extend(inner_pat.iter());
+                    pats.extend(post_pats.iter());
+                }
+                _ => {}
             }
         }
+
+        pat.each_binding(|_, hir_id, _, ident| {
+            self.add_live_node_for_node(hir_id, VarDefNode(ident.span));
+            self.add_variable(Local(LocalInfo {
+                id: hir_id,
+                name: ident.name,
+                is_shorthand: shorthand_field_ids.contains(&hir_id),
+            }));
+        });
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::OnlyBodies(self.tcx.hir())
     }
 
-    debug!("creating fn_maps: {:p}", &fn_maps);
+    fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
+        debug!("visit_body {:?}", body.id());
 
-    let body = ir.tcx.hir().body(body_id);
+        // swap in a new set of IR maps for this body
+        let mut maps = IrMaps::new(self.tcx);
+        let hir_id = maps.tcx.hir().body_owner(body.id());
+        let def_id = maps.tcx.hir().local_def_id(hir_id);
 
-    if let Some(upvars) = ir.tcx.upvars_mentioned(def_id) {
-        for (&var_hir_id, _upvar) in upvars {
-            let var_name = ir.tcx.hir().name(var_hir_id);
-            fn_maps.add_variable(Upvar(var_hir_id, var_name));
+        // Don't run unused pass for #[derive()]
+        if let Some(parent) = self.tcx.parent(def_id.to_def_id()) {
+            if let DefKind::Impl = self.tcx.def_kind(parent.expect_local()) {
+                if self.tcx.has_attr(parent, sym::automatically_derived) {
+                    return;
+                }
+            }
         }
+
+        if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) {
+            for (&var_hir_id, _upvar) in upvars {
+                let var_name = maps.tcx.hir().name(var_hir_id);
+                maps.add_variable(Upvar(var_hir_id, var_name));
+            }
+        }
+
+        // gather up the various local variables, significant expressions,
+        // and so forth:
+        intravisit::walk_body(&mut maps, body);
+
+        // compute liveness
+        let mut lsets = Liveness::new(&mut maps, def_id);
+        let entry_ln = lsets.compute(&body, hir_id);
+        lsets.log_liveness(entry_ln, body.id().hir_id);
+
+        // check for various error conditions
+        lsets.visit_body(body);
+        lsets.warn_about_unused_upvars(entry_ln);
+        lsets.warn_about_unused_args(body, entry_ln);
     }
 
-    for param in body.params {
+    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+        self.add_from_pat(&local.pat);
+        intravisit::walk_local(self, local);
+    }
+
+    fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
+        self.add_from_pat(&arm.pat);
+        intravisit::walk_arm(self, arm);
+    }
+
+    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
         let is_shorthand = match param.pat.kind {
             rustc_hir::PatKind::Struct(..) => true,
             _ => false,
@@ -350,150 +371,84 @@
             } else {
                 Param(hir_id, ident.name)
             };
-            fn_maps.add_variable(var);
-        })
+            self.add_variable(var);
+        });
+        intravisit::walk_param(self, param);
     }
 
-    // gather up the various local variables, significant expressions,
-    // and so forth:
-    intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
-
-    // compute liveness
-    let mut lsets = Liveness::new(&mut fn_maps, def_id);
-    let entry_ln = lsets.compute(fk, &body, sp, id);
-    lsets.log_liveness(entry_ln, id);
-
-    // check for various error conditions
-    lsets.visit_body(body);
-    lsets.warn_about_unused_upvars(entry_ln);
-    lsets.warn_about_unused_args(body, entry_ln);
-}
-
-fn add_from_pat(ir: &mut IrMaps<'_>, pat: &hir::Pat<'_>) {
-    // For struct patterns, take note of which fields used shorthand
-    // (`x` rather than `x: x`).
-    let mut shorthand_field_ids = HirIdSet::default();
-    let mut pats = VecDeque::new();
-    pats.push_back(pat);
-    while let Some(pat) = pats.pop_front() {
-        use rustc_hir::PatKind::*;
-        match &pat.kind {
-            Binding(.., inner_pat) => {
-                pats.extend(inner_pat.iter());
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        match expr.kind {
+            // live nodes required for uses or definitions of variables:
+            hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
+                debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
+                if let Res::Local(_var_hir_id) = path.res {
+                    self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+                }
+                intravisit::walk_expr(self, expr);
             }
-            Struct(_, fields, _) => {
-                let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id);
-                shorthand_field_ids.extend(ids);
+            hir::ExprKind::Closure(..) => {
+                // Interesting control flow (for loops can contain labeled
+                // breaks or continues)
+                self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+
+                // Make a live_node for each captured variable, with the span
+                // being the location that the variable is used.  This results
+                // in better error messages than just pointing at the closure
+                // construction site.
+                let mut call_caps = Vec::new();
+                let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id);
+                if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
+                    call_caps.extend(upvars.iter().map(|(&var_id, upvar)| {
+                        let upvar_ln = self.add_live_node(UpvarNode(upvar.span));
+                        CaptureInfo { ln: upvar_ln, var_hid: var_id }
+                    }));
+                }
+                self.set_captures(expr.hir_id, call_caps);
+                intravisit::walk_expr(self, expr);
             }
-            Ref(inner_pat, _) | Box(inner_pat) => {
-                pats.push_back(inner_pat);
+
+            // live nodes required for interesting control flow:
+            hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
+                self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+                intravisit::walk_expr(self, expr);
             }
-            TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => {
-                pats.extend(inner_pats.iter());
+            hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => {
+                self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+                intravisit::walk_expr(self, expr);
             }
-            Slice(pre_pats, inner_pat, post_pats) => {
-                pats.extend(pre_pats.iter());
-                pats.extend(inner_pat.iter());
-                pats.extend(post_pats.iter());
+
+            // otherwise, live nodes are not required:
+            hir::ExprKind::Index(..)
+            | hir::ExprKind::Field(..)
+            | hir::ExprKind::Array(..)
+            | hir::ExprKind::Call(..)
+            | hir::ExprKind::MethodCall(..)
+            | hir::ExprKind::Tup(..)
+            | hir::ExprKind::Binary(..)
+            | hir::ExprKind::AddrOf(..)
+            | hir::ExprKind::Cast(..)
+            | hir::ExprKind::DropTemps(..)
+            | hir::ExprKind::Unary(..)
+            | hir::ExprKind::Break(..)
+            | hir::ExprKind::Continue(_)
+            | hir::ExprKind::Lit(_)
+            | hir::ExprKind::ConstBlock(..)
+            | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Block(..)
+            | hir::ExprKind::Assign(..)
+            | hir::ExprKind::AssignOp(..)
+            | hir::ExprKind::Struct(..)
+            | hir::ExprKind::Repeat(..)
+            | hir::ExprKind::InlineAsm(..)
+            | hir::ExprKind::LlvmInlineAsm(..)
+            | hir::ExprKind::Box(..)
+            | hir::ExprKind::Yield(..)
+            | hir::ExprKind::Type(..)
+            | hir::ExprKind::Err
+            | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
+            | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {
+                intravisit::walk_expr(self, expr);
             }
-            _ => {}
-        }
-    }
-
-    pat.each_binding(|_, hir_id, _, ident| {
-        ir.add_live_node_for_node(hir_id, VarDefNode(ident.span));
-        ir.add_variable(Local(LocalInfo {
-            id: hir_id,
-            name: ident.name,
-            is_shorthand: shorthand_field_ids.contains(&hir_id),
-        }));
-    });
-}
-
-fn visit_local<'tcx>(ir: &mut IrMaps<'tcx>, local: &'tcx hir::Local<'tcx>) {
-    add_from_pat(ir, &local.pat);
-    intravisit::walk_local(ir, local);
-}
-
-fn visit_arm<'tcx>(ir: &mut IrMaps<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
-    add_from_pat(ir, &arm.pat);
-    intravisit::walk_arm(ir, arm);
-}
-
-fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
-    match expr.kind {
-        // live nodes required for uses or definitions of variables:
-        hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
-            debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
-            if let Res::Local(_var_hir_id) = path.res {
-                ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-            }
-            intravisit::walk_expr(ir, expr);
-        }
-        hir::ExprKind::Closure(..) => {
-            // Interesting control flow (for loops can contain labeled
-            // breaks or continues)
-            ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-
-            // Make a live_node for each captured variable, with the span
-            // being the location that the variable is used.  This results
-            // in better error messages than just pointing at the closure
-            // construction site.
-            let mut call_caps = Vec::new();
-            let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id);
-            if let Some(upvars) = ir.tcx.upvars_mentioned(closure_def_id) {
-                call_caps.extend(upvars.iter().map(|(&var_id, upvar)| {
-                    let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
-                    CaptureInfo { ln: upvar_ln, var_hid: var_id }
-                }));
-            }
-            ir.set_captures(expr.hir_id, call_caps);
-            let old_body_owner = ir.body_owner;
-            ir.body_owner = closure_def_id;
-            intravisit::walk_expr(ir, expr);
-            ir.body_owner = old_body_owner;
-        }
-
-        // live nodes required for interesting control flow:
-        hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
-            ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-            intravisit::walk_expr(ir, expr);
-        }
-        hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => {
-            ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
-            intravisit::walk_expr(ir, expr);
-        }
-
-        // otherwise, live nodes are not required:
-        hir::ExprKind::Index(..)
-        | hir::ExprKind::Field(..)
-        | hir::ExprKind::Array(..)
-        | hir::ExprKind::Call(..)
-        | hir::ExprKind::MethodCall(..)
-        | hir::ExprKind::Tup(..)
-        | hir::ExprKind::Binary(..)
-        | hir::ExprKind::AddrOf(..)
-        | hir::ExprKind::Cast(..)
-        | hir::ExprKind::DropTemps(..)
-        | hir::ExprKind::Unary(..)
-        | hir::ExprKind::Break(..)
-        | hir::ExprKind::Continue(_)
-        | hir::ExprKind::Lit(_)
-        | hir::ExprKind::Ret(..)
-        | hir::ExprKind::Block(..)
-        | hir::ExprKind::Assign(..)
-        | hir::ExprKind::AssignOp(..)
-        | hir::ExprKind::Struct(..)
-        | hir::ExprKind::Repeat(..)
-        | hir::ExprKind::InlineAsm(..)
-        | hir::ExprKind::LlvmInlineAsm(..)
-        | hir::ExprKind::Box(..)
-        | hir::ExprKind::Yield(..)
-        | hir::ExprKind::Type(..)
-        | hir::ExprKind::Err
-        | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
-        | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {
-            intravisit::walk_expr(ir, expr);
         }
     }
 }
@@ -506,8 +461,8 @@
 
 #[derive(Clone, Copy)]
 struct RWU {
-    reader: LiveNode,
-    writer: LiveNode,
+    reader: Option<LiveNode>,
+    writer: Option<LiveNode>,
     used: bool,
 }
 
@@ -529,10 +484,10 @@
     unpacked_rwus: Vec<RWU>,
 }
 
-// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: false }`.
+// A constant representing `RWU { reader: None; writer: None; used: false }`.
 const INV_INV_FALSE: u32 = u32::MAX;
 
-// A constant representing `RWU { reader: INVALID_NODE; writer: INVALID_NODE; used: true }`.
+// A constant representing `RWU { reader: None; writer: None; used: true }`.
 const INV_INV_TRUE: u32 = u32::MAX - 1;
 
 impl RWUTable {
@@ -543,24 +498,24 @@
     fn get(&self, idx: usize) -> RWU {
         let packed_rwu = self.packed_rwus[idx];
         match packed_rwu {
-            INV_INV_FALSE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: false },
-            INV_INV_TRUE => RWU { reader: INVALID_NODE, writer: INVALID_NODE, used: true },
+            INV_INV_FALSE => RWU { reader: None, writer: None, used: false },
+            INV_INV_TRUE => RWU { reader: None, writer: None, used: true },
             _ => self.unpacked_rwus[packed_rwu as usize],
         }
     }
 
-    fn get_reader(&self, idx: usize) -> LiveNode {
+    fn get_reader(&self, idx: usize) -> Option<LiveNode> {
         let packed_rwu = self.packed_rwus[idx];
         match packed_rwu {
-            INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE,
+            INV_INV_FALSE | INV_INV_TRUE => None,
             _ => self.unpacked_rwus[packed_rwu as usize].reader,
         }
     }
 
-    fn get_writer(&self, idx: usize) -> LiveNode {
+    fn get_writer(&self, idx: usize) -> Option<LiveNode> {
         let packed_rwu = self.packed_rwus[idx];
         match packed_rwu {
-            INV_INV_FALSE | INV_INV_TRUE => INVALID_NODE,
+            INV_INV_FALSE | INV_INV_TRUE => None,
             _ => self.unpacked_rwus[packed_rwu as usize].writer,
         }
     }
@@ -580,7 +535,7 @@
     }
 
     fn assign_unpacked(&mut self, idx: usize, rwu: RWU) {
-        if rwu.reader == INVALID_NODE && rwu.writer == INVALID_NODE {
+        if rwu.reader == None && rwu.writer == None {
             // When we overwrite an indexing entry in `self.packed_rwus` with
             // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry
             // from `self.unpacked_rwus`; it's not worth the effort, and we
@@ -605,9 +560,11 @@
 
 struct Liveness<'a, 'tcx> {
     ir: &'a mut IrMaps<'tcx>,
+    body_owner: LocalDefId,
     typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    successors: IndexVec<LiveNode, LiveNode>,
+    upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
+    successors: IndexVec<LiveNode, Option<LiveNode>>,
     rwu_table: RWUTable,
 
     /// A live node representing a point of execution before closure entry &
@@ -626,9 +583,10 @@
 }
 
 impl<'a, 'tcx> Liveness<'a, 'tcx> {
-    fn new(ir: &'a mut IrMaps<'tcx>, def_id: LocalDefId) -> Liveness<'a, 'tcx> {
-        let typeck_results = ir.tcx.typeck(def_id);
-        let param_env = ir.tcx.param_env(def_id);
+    fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> {
+        let typeck_results = ir.tcx.typeck(body_owner);
+        let param_env = ir.tcx.param_env(body_owner);
+        let upvars = ir.tcx.upvars_mentioned(body_owner);
 
         let closure_ln = ir.add_live_node(ClosureNode);
         let exit_ln = ir.add_live_node(ExitNode);
@@ -638,9 +596,11 @@
 
         Liveness {
             ir,
+            body_owner,
             typeck_results,
             param_env,
-            successors: IndexVec::from_elem_n(INVALID_NODE, num_live_nodes),
+            upvars,
+            successors: IndexVec::from_elem_n(None, num_live_nodes),
             rwu_table: RWUTable::new(num_live_nodes * num_vars),
             closure_ln,
             exit_ln,
@@ -685,30 +645,33 @@
     }
 
     fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
-        assert!(ln.is_valid());
-        let reader = self.rwu_table.get_reader(self.idx(ln, var));
-        if reader.is_valid() { Some(self.ir.lnks[reader]) } else { None }
+        if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) {
+            Some(self.ir.lnks[reader])
+        } else {
+            None
+        }
     }
 
     // Is this variable live on entry to any of its successor nodes?
     fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
-        let successor = self.successors[ln];
+        let successor = self.successors[ln].unwrap();
         self.live_on_entry(successor, var)
     }
 
     fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
-        assert!(ln.is_valid());
         self.rwu_table.get_used(self.idx(ln, var))
     }
 
     fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
-        assert!(ln.is_valid());
-        let writer = self.rwu_table.get_writer(self.idx(ln, var));
-        if writer.is_valid() { Some(self.ir.lnks[writer]) } else { None }
+        if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) {
+            Some(self.ir.lnks[writer])
+        } else {
+            None
+        }
     }
 
     fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option<LiveNodeKind> {
-        let successor = self.successors[ln];
+        let successor = self.successors[ln].unwrap();
         self.assigned_on_entry(successor, var)
     }
 
@@ -743,9 +706,9 @@
         {
             let wr = &mut wr as &mut dyn Write;
             write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]);
-            self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid());
+            self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some());
             write!(wr, "  writes");
-            self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid());
+            self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some());
             write!(wr, "  uses");
             self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx));
 
@@ -769,7 +732,7 @@
     }
 
     fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) {
-        self.successors[ln] = succ_ln;
+        self.successors[ln] = Some(succ_ln);
 
         // It is not necessary to initialize the RWUs here because they are all
         // set to INV_INV_FALSE when they are created, and the sets only grow
@@ -778,7 +741,7 @@
 
     fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) {
         // more efficient version of init_empty() / merge_from_succ()
-        self.successors[ln] = succ_ln;
+        self.successors[ln] = Some(succ_ln);
 
         self.indices2(ln, succ_ln, |this, idx, succ_idx| {
             this.rwu_table.copy_packed(idx, succ_idx);
@@ -802,12 +765,12 @@
             let mut changed = false;
             let mut rwu = this.rwu_table.get(idx);
             let succ_rwu = this.rwu_table.get(succ_idx);
-            if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() {
+            if succ_rwu.reader.is_some() && rwu.reader.is_none() {
                 rwu.reader = succ_rwu.reader;
                 changed = true
             }
 
-            if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() {
+            if succ_rwu.writer.is_some() && rwu.writer.is_none() {
                 rwu.writer = succ_rwu.writer;
                 changed = true
             }
@@ -851,14 +814,14 @@
         let mut rwu = self.rwu_table.get(idx);
 
         if (acc & ACC_WRITE) != 0 {
-            rwu.reader = INVALID_NODE;
-            rwu.writer = ln;
+            rwu.reader = None;
+            rwu.writer = Some(ln);
         }
 
         // Important: if we both read/write, must do read second
         // or else the write will override.
         if (acc & ACC_READ) != 0 {
-            rwu.reader = ln;
+            rwu.reader = Some(ln);
         }
 
         if (acc & ACC_USE) != 0 {
@@ -868,14 +831,8 @@
         self.rwu_table.assign_unpacked(idx, rwu);
     }
 
-    fn compute(
-        &mut self,
-        fk: FnKind<'_>,
-        body: &hir::Body<'_>,
-        span: Span,
-        id: hir::HirId,
-    ) -> LiveNode {
-        debug!("compute: using id for body, {:?}", body.value);
+    fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode {
+        debug!("compute: for body {:?}", body.id().hir_id);
 
         // # Liveness of captured variables
         //
@@ -893,12 +850,12 @@
         // if they are live on the entry to the closure, since only the closure
         // itself can access them on subsequent calls.
 
-        if let Some(upvars) = self.ir.tcx.upvars_mentioned(self.ir.body_owner) {
+        if let Some(upvars) = self.upvars {
             // Mark upvars captured by reference as used after closure exits.
             for (&var_hir_id, upvar) in upvars.iter().rev() {
                 let upvar_id = ty::UpvarId {
                     var_path: ty::UpvarPath { hir_id: var_hir_id },
-                    closure_expr_id: self.ir.body_owner,
+                    closure_expr_id: self.body_owner,
                 };
                 match self.typeck_results.upvar_capture(upvar_id) {
                     ty::UpvarCapture::ByRef(_) => {
@@ -912,12 +869,14 @@
 
         let succ = self.propagate_through_expr(&body.value, self.exit_ln);
 
-        match fk {
-            FnKind::Method(..) | FnKind::ItemFn(..) => return succ,
-            FnKind::Closure(..) => {}
+        if self.upvars.is_none() {
+            // Either not a closure, or closure without any captured variables.
+            // No need to determine liveness of captured variables, since there
+            // are none.
+            return succ;
         }
 
-        let ty = self.typeck_results.node_type(id);
+        let ty = self.typeck_results.node_type(hir_id);
         match ty.kind() {
             ty::Closure(_def_id, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => {}
@@ -926,7 +885,12 @@
             },
             ty::Generator(..) => return succ,
             _ => {
-                span_bug!(span, "type of closure expr {:?} is not a closure {:?}", id, ty,);
+                span_bug!(
+                    body.value.span,
+                    "{} has upvars so it should have a closure type: {:?}",
+                    hir_id,
+                    ty
+                );
             }
         };
 
@@ -1210,7 +1174,7 @@
                             }
                         }
                         hir::InlineAsmOperand::InOut { expr, .. } => {
-                            succ = self.write_place(expr, succ, ACC_READ | ACC_WRITE);
+                            succ = self.write_place(expr, succ, ACC_READ | ACC_WRITE | ACC_USE);
                         }
                         hir::InlineAsmOperand::SplitInOut { out_expr, .. } => {
                             if let Some(expr) = out_expr {
@@ -1269,6 +1233,7 @@
             }
 
             hir::ExprKind::Lit(..)
+            | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Err
             | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
             | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ,
@@ -1515,6 +1480,7 @@
         | hir::ExprKind::Break(..)
         | hir::ExprKind::Continue(..)
         | hir::ExprKind::Lit(_)
+        | hir::ExprKind::ConstBlock(..)
         | hir::ExprKind::Block(..)
         | hir::ExprKind::AddrOf(..)
         | hir::ExprKind::Struct(..)
@@ -1565,7 +1531,7 @@
     }
 
     fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
-        let upvars = match self.ir.tcx.upvars_mentioned(self.ir.body_owner) {
+        let upvars = match self.upvars {
             None => return,
             Some(upvars) => upvars,
         };
@@ -1573,7 +1539,7 @@
             let var = self.variable(var_hir_id, upvar.span);
             let upvar_id = ty::UpvarId {
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
-                closure_expr_id: self.ir.body_owner,
+                closure_expr_id: self.body_owner,
             };
             match self.typeck_results.upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue(_) => {}
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 1378b0d..c9497f2 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -13,15 +13,13 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability::{DeprecationEntry, Index};
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, query::Providers, TyCtxt};
 use rustc_session::lint;
 use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
-use rustc_trait_selection::traits::misc::can_type_implement_copy;
+use rustc_span::{Span, DUMMY_SP};
 
 use std::cmp::Ordering;
 use std::mem::replace;
@@ -711,27 +709,35 @@
             // so semi-randomly perform it here in stability.rs
             hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => {
                 let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                let adt_def = self.tcx.adt_def(def_id);
                 let ty = self.tcx.type_of(def_id);
+                let (adt_def, substs) = match ty.kind() {
+                    ty::Adt(adt_def, substs) => (adt_def, substs),
+                    _ => bug!(),
+                };
 
-                if adt_def.has_dtor(self.tcx) {
-                    feature_err(
-                        &self.tcx.sess.parse_sess,
-                        sym::untagged_unions,
-                        item.span,
-                        "unions with `Drop` implementations are unstable",
-                    )
-                    .emit();
-                } else {
-                    let param_env = self.tcx.param_env(def_id);
-                    if can_type_implement_copy(self.tcx, param_env, ty).is_err() {
-                        feature_err(
-                            &self.tcx.sess.parse_sess,
-                            sym::untagged_unions,
-                            item.span,
-                            "unions with non-`Copy` fields are unstable",
-                        )
-                        .emit();
+                // Non-`Copy` fields are unstable, except for `ManuallyDrop`.
+                let param_env = self.tcx.param_env(def_id);
+                for field in &adt_def.non_enum_variant().fields {
+                    let field_ty = field.ty(self.tcx, substs);
+                    if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
+                        && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env)
+                    {
+                        if field_ty.needs_drop(self.tcx, param_env) {
+                            // Avoid duplicate error: This will error later anyway because fields
+                            // that need drop are not allowed.
+                            self.tcx.sess.delay_span_bug(
+                                item.span,
+                                "union should have been rejected due to potentially dropping field",
+                            );
+                        } else {
+                            feature_err(
+                                &self.tcx.sess.parse_sess,
+                                sym::untagged_unions,
+                                self.tcx.def_span(field.did),
+                                "unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable",
+                            )
+                            .emit();
+                        }
                     }
                 }
             }
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 6bc2110..8650ee0 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -26,7 +26,7 @@
     if items.eh_personality().is_none() {
         items.missing.push(LangItem::EhPersonality);
     }
-    if tcx.sess.target.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
+    if tcx.sess.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
         items.missing.push(LangItem::EhCatchTypeinfo);
     }
 
@@ -64,7 +64,10 @@
             if item == LangItem::PanicImpl {
                 tcx.sess.err("`#[panic_handler]` function required, but not found");
             } else if item == LangItem::Oom {
-                tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
+                if !tcx.features().default_alloc_error_handler {
+                    tcx.sess.err("`#[alloc_error_handler]` function required, but not found.");
+                    tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler.");
+                }
             } else {
                 tcx.sess.err(&format!("language item required, but not found: `{}`", name));
             }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 8d1b826..851e0df 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,6 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
+#![feature(or_patterns)]
 #![recursion_limit = "256"]
 
 use rustc_attr as attr;
@@ -14,13 +15,14 @@
 use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
+use rustc_middle::span_bug;
 use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 
 use std::marker::PhantomData;
@@ -194,11 +196,14 @@
                     // The intent is to treat `impl Trait1 + Trait2` identically to
                     // `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
                     // (it either has no visibility, or its visibility is insignificant, like
-                    // visibilities of type aliases) and recurse into predicates instead to go
+                    // visibilities of type aliases) and recurse into bounds instead to go
                     // through the trait list (default type visitor doesn't visit those traits).
                     // All traits in the list are considered the "primary" part of the type
                     // and are visited by shallow visitors.
-                    if self.visit_predicates(tcx.predicates_of(def_id)) {
+                    if self.visit_predicates(ty::GenericPredicates {
+                        parent: None,
+                        predicates: tcx.explicit_item_bounds(def_id),
+                    }) {
                         return true;
                     }
                 }
@@ -230,125 +235,6 @@
     }
 }
 
-fn def_id_visibility<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-) -> (ty::Visibility, Span, &'static str) {
-    match def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) {
-        Some(hir_id) => {
-            let vis = match tcx.hir().get(hir_id) {
-                Node::Item(item) => &item.vis,
-                Node::ForeignItem(foreign_item) => &foreign_item.vis,
-                Node::MacroDef(macro_def) => {
-                    if tcx.sess.contains_name(&macro_def.attrs, sym::macro_export) {
-                        return (ty::Visibility::Public, macro_def.span, "public");
-                    } else {
-                        &macro_def.vis
-                    }
-                }
-                Node::TraitItem(..) | Node::Variant(..) => {
-                    return def_id_visibility(tcx, tcx.hir().get_parent_did(hir_id).to_def_id());
-                }
-                Node::ImplItem(impl_item) => {
-                    match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) {
-                        Node::Item(item) => match &item.kind {
-                            hir::ItemKind::Impl { of_trait: None, .. } => &impl_item.vis,
-                            hir::ItemKind::Impl { of_trait: Some(trait_ref), .. } => {
-                                return def_id_visibility(tcx, trait_ref.path.res.def_id());
-                            }
-                            kind => bug!("unexpected item kind: {:?}", kind),
-                        },
-                        node => bug!("unexpected node kind: {:?}", node),
-                    }
-                }
-                Node::Ctor(vdata) => {
-                    let parent_hir_id = tcx.hir().get_parent_node(hir_id);
-                    match tcx.hir().get(parent_hir_id) {
-                        Node::Variant(..) => {
-                            let parent_did = tcx.hir().local_def_id(parent_hir_id);
-                            let (mut ctor_vis, mut span, mut descr) =
-                                def_id_visibility(tcx, parent_did.to_def_id());
-
-                            let adt_def = tcx.adt_def(tcx.hir().get_parent_did(hir_id).to_def_id());
-                            let ctor_did = tcx.hir().local_def_id(vdata.ctor_hir_id().unwrap());
-                            let variant = adt_def.variant_with_ctor_id(ctor_did.to_def_id());
-
-                            if variant.is_field_list_non_exhaustive()
-                                && ctor_vis == ty::Visibility::Public
-                            {
-                                ctor_vis =
-                                    ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-                                let attrs = tcx.get_attrs(variant.def_id);
-                                span = tcx
-                                    .sess
-                                    .find_by_name(&attrs, sym::non_exhaustive)
-                                    .unwrap()
-                                    .span;
-                                descr = "crate-visible";
-                            }
-
-                            return (ctor_vis, span, descr);
-                        }
-                        Node::Item(..) => {
-                            let item = match tcx.hir().get(parent_hir_id) {
-                                Node::Item(item) => item,
-                                node => bug!("unexpected node kind: {:?}", node),
-                            };
-                            let (mut ctor_vis, mut span, mut descr) = (
-                                ty::Visibility::from_hir(&item.vis, parent_hir_id, tcx),
-                                item.vis.span,
-                                item.vis.node.descr(),
-                            );
-                            for field in vdata.fields() {
-                                let field_vis = ty::Visibility::from_hir(&field.vis, hir_id, tcx);
-                                if ctor_vis.is_at_least(field_vis, tcx) {
-                                    ctor_vis = field_vis;
-                                    span = field.vis.span;
-                                    descr = field.vis.node.descr();
-                                }
-                            }
-
-                            // If the structure is marked as non_exhaustive then lower the
-                            // visibility to within the crate.
-                            if ctor_vis == ty::Visibility::Public {
-                                let adt_def =
-                                    tcx.adt_def(tcx.hir().get_parent_did(hir_id).to_def_id());
-                                if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
-                                    ctor_vis =
-                                        ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-                                    span = tcx
-                                        .sess
-                                        .find_by_name(&item.attrs, sym::non_exhaustive)
-                                        .unwrap()
-                                        .span;
-                                    descr = "crate-visible";
-                                }
-                            }
-
-                            return (ctor_vis, span, descr);
-                        }
-                        node => bug!("unexpected node kind: {:?}", node),
-                    }
-                }
-                Node::Expr(expr) => {
-                    return (
-                        ty::Visibility::Restricted(tcx.parent_module(expr.hir_id).to_def_id()),
-                        expr.span,
-                        "private",
-                    );
-                }
-                node => bug!("unexpected node kind: {:?}", node),
-            };
-            (ty::Visibility::from_hir(vis, hir_id, tcx), vis.span, vis.node.descr())
-        }
-        None => {
-            let vis = tcx.visibility(def_id);
-            let descr = if vis == ty::Visibility::Public { "public" } else { "private" };
-            (vis, tcx.def_span(def_id), descr)
-        }
-    }
-}
-
 fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
     if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
 }
@@ -421,7 +307,7 @@
 impl VisibilityLike for ty::Visibility {
     const MAX: Self = ty::Visibility::Public;
     fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
-        min(def_id_visibility(find.tcx, def_id).0, find.min, find.tcx)
+        min(find.tcx.visibility(def_id), find.min, find.tcx)
     }
 }
 impl VisibilityLike for Option<AccessLevel> {
@@ -531,17 +417,16 @@
             let hir_id = item_id.id;
             let item_def_id = self.tcx.hir().local_def_id(hir_id);
             let def_kind = self.tcx.def_kind(item_def_id);
-            let item = self.tcx.hir().expect_item(hir_id);
-            let vis = ty::Visibility::from_hir(&item.vis, hir_id, self.tcx);
+            let vis = self.tcx.visibility(item_def_id);
             self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
         }
         if let Some(exports) = self.tcx.module_exports(module_def_id) {
             for export in exports {
                 if export.vis.is_accessible_from(defining_mod, self.tcx) {
                     if let Res::Def(def_kind, def_id) = export.res {
-                        let vis = def_id_visibility(self.tcx, def_id).0;
                         if let Some(def_id) = def_id.as_local() {
                             let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                            let vis = self.tcx.visibility(def_id.to_def_id());
                             self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
                         }
                     }
@@ -593,7 +478,7 @@
                     {
                         for field in struct_def.fields() {
                             let field_vis =
-                                ty::Visibility::from_hir(&field.vis, field.hir_id, self.tcx);
+                                self.tcx.visibility(self.tcx.hir().local_def_id(field.hir_id));
                             if field_vis.is_accessible_from(module, self.tcx) {
                                 self.reach(field.hir_id, level).ty();
                             }
@@ -1012,11 +897,10 @@
     }
     fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
         if let Some(def_id) = def_id.as_local() {
-            let hir_id = self.ev.tcx.hir().local_def_id_to_hir_id(def_id);
-            if let ((ty::Visibility::Public, ..), _)
-            | (_, Some(AccessLevel::ReachableFromImplTrait)) =
-                (def_id_visibility(self.tcx(), def_id.to_def_id()), self.access_level)
+            if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
+                (self.tcx().visibility(def_id.to_def_id()), self.access_level)
             {
+                let hir_id = self.ev.tcx.hir().local_def_id_to_hir_id(def_id);
                 self.ev.update(hir_id, self.access_level);
             }
         }
@@ -1181,9 +1065,7 @@
     }
 
     fn item_is_accessible(&self, did: DefId) -> bool {
-        def_id_visibility(self.tcx, did)
-            .0
-            .is_accessible_from(self.current_item.to_def_id(), self.tcx)
+        self.tcx.visibility(did).is_accessible_from(self.current_item.to_def_id(), self.tcx)
     }
 
     // Take node-id of an expression or pattern and check its type for privacy.
@@ -1800,6 +1682,14 @@
         self
     }
 
+    fn bounds(&mut self) -> &mut Self {
+        self.visit_predicates(ty::GenericPredicates {
+            parent: None,
+            predicates: self.tcx.explicit_item_bounds(self.item_def_id),
+        });
+        self
+    }
+
     fn ty(&mut self) -> &mut Self {
         self.visit(self.tcx.type_of(self.item_def_id));
         self
@@ -1829,8 +1719,21 @@
             None => return false,
         };
 
-        let (vis, vis_span, vis_descr) = def_id_visibility(self.tcx, def_id);
+        let vis = self.tcx.visibility(def_id);
         if !vis.is_at_least(self.required_visibility, self.tcx) {
+            let vis_descr = match vis {
+                ty::Visibility::Public => "public",
+                ty::Visibility::Invisible => "private",
+                ty::Visibility::Restricted(vis_def_id) => {
+                    if vis_def_id == self.tcx.parent_module(hir_id).to_def_id() {
+                        "private"
+                    } else if vis_def_id.is_top_level_module() {
+                        "crate-private"
+                    } else {
+                        "restricted"
+                    }
+                }
+            };
             let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
             if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
                 let mut err = if kind == "trait" {
@@ -1838,6 +1741,8 @@
                 } else {
                     struct_span_err!(self.tcx.sess, self.span, E0446, "{}", make_msg())
                 };
+                let vis_span =
+                    self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
                 err.span_label(self.span, format!("can't leak {} {}", vis_descr, kind));
                 err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
                 err.emit();
@@ -1954,7 +1859,7 @@
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let tcx = self.tcx;
-        let item_visibility = ty::Visibility::from_hir(&item.vis, item.hir_id, tcx);
+        let item_visibility = tcx.visibility(tcx.hir().local_def_id(item.hir_id).to_def_id());
 
         match item.kind {
             // Crates are always public.
@@ -1975,7 +1880,7 @@
             hir::ItemKind::OpaqueTy(..) => {
                 // `ty()` for opaque types is the underlying type,
                 // it's not a part of interface, so we skip it.
-                self.check(item.hir_id, item_visibility).generics().predicates();
+                self.check(item.hir_id, item_visibility).generics().bounds();
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 self.check(item.hir_id, item_visibility).generics().predicates();
@@ -1987,6 +1892,10 @@
                         trait_item_ref.defaultness,
                         item_visibility,
                     );
+
+                    if let AssocItemKind::Type = trait_item_ref.kind {
+                        self.check(trait_item_ref.id.hir_id, item_visibility).bounds();
+                    }
                 }
             }
             hir::ItemKind::TraitAlias(..) => {
@@ -2004,7 +1913,7 @@
             // Subitems of foreign modules have their own publicity.
             hir::ItemKind::ForeignMod(ref foreign_mod) => {
                 for foreign_item in foreign_mod.items {
-                    let vis = ty::Visibility::from_hir(&foreign_item.vis, item.hir_id, tcx);
+                    let vis = tcx.visibility(tcx.hir().local_def_id(foreign_item.hir_id));
                     self.check(foreign_item.hir_id, vis).generics().predicates().ty();
                 }
             }
@@ -2013,7 +1922,7 @@
                 self.check(item.hir_id, item_visibility).generics().predicates();
 
                 for field in struct_def.fields() {
-                    let field_visibility = ty::Visibility::from_hir(&field.vis, item.hir_id, tcx);
+                    let field_visibility = tcx.visibility(tcx.hir().local_def_id(field.hir_id));
                     self.check(field.hir_id, min(item_visibility, field_visibility, tcx)).ty();
                 }
             }
@@ -2025,10 +1934,9 @@
                 let impl_vis = ty::Visibility::of_impl(item.hir_id, tcx, &Default::default());
                 self.check(item.hir_id, impl_vis).generics().predicates();
                 for impl_item_ref in items {
-                    let impl_item = tcx.hir().impl_item(impl_item_ref.id);
                     let impl_item_vis = if of_trait.is_none() {
                         min(
-                            ty::Visibility::from_hir(&impl_item.vis, item.hir_id, tcx),
+                            tcx.visibility(tcx.hir().local_def_id(impl_item_ref.id.hir_id)),
                             impl_vis,
                             tcx,
                         )
@@ -2049,6 +1957,7 @@
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
+        visibility,
         privacy_access_levels,
         check_private_in_public,
         check_mod_privacy,
@@ -2056,6 +1965,55 @@
     };
 }
 
+fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
+    let def_id = def_id.expect_local();
+    match tcx.visibilities.get(&def_id) {
+        Some(vis) => *vis,
+        None => {
+            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+            match tcx.hir().get(hir_id) {
+                // Unique types created for closures participate in type privacy checking.
+                // They have visibilities inherited from the module they are defined in.
+                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
+                    ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id())
+                }
+                // - AST lowering may clone `use` items and the clones don't
+                //   get their entries in the resolver's visibility table.
+                // - AST lowering also creates opaque type items with inherited visibilies.
+                //   Visibility on them should have no effect, but to avoid the visibility
+                //   query failing on some items, we provide it for opaque types as well.
+                Node::Item(hir::Item {
+                    vis,
+                    kind: hir::ItemKind::Use(..) | hir::ItemKind::OpaqueTy(..),
+                    ..
+                }) => ty::Visibility::from_hir(vis, hir_id, tcx),
+                // Visibilities of trait impl items are inherited from their traits
+                // and are not filled in resolve.
+                Node::ImplItem(impl_item) => {
+                    match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) {
+                        Node::Item(hir::Item {
+                            kind: hir::ItemKind::Impl { of_trait: Some(tr), .. },
+                            ..
+                        }) => tr.path.res.opt_def_id().map_or_else(
+                            || {
+                                tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id");
+                                ty::Visibility::Public
+                            },
+                            |def_id| tcx.visibility(def_id),
+                        ),
+                        _ => span_bug!(impl_item.span, "the parent is not a trait impl"),
+                    }
+                }
+                _ => span_bug!(
+                    tcx.def_span(def_id),
+                    "visibility table unexpectedly missing a def-id: {:?}",
+                    def_id,
+                ),
+            }
+        }
+    }
+}
+
 fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     // Check privacy of names not checked in previous compilation stages.
     let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: None };
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index e302784..7808a28 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -165,10 +165,6 @@
         cgu_name.hash(&mut hasher);
         WorkProductId { hash: hasher.finish() }
     }
-
-    pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId {
-        WorkProductId { hash: fingerprint }
-    }
 }
 
 impl<HCX> HashStable<HCX> for WorkProductId {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index d70306b..85335f0 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -402,11 +402,6 @@
         self.data.as_ref().unwrap().previous.fingerprint_of(dep_node)
     }
 
-    #[inline]
-    pub fn prev_dep_node_index_of(&self, dep_node: &DepNode<K>) -> SerializedDepNodeIndex {
-        self.data.as_ref().unwrap().previous.node_to_index(dep_node)
-    }
-
     /// Checks whether a previous work product exists for `v` and, if
     /// so, return the path that leads to it. Used to skip doing work.
     pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs
index fb313d2..a27b716 100644
--- a/compiler/rustc_query_system/src/dep_graph/query.rs
+++ b/compiler/rustc_query_system/src/dep_graph/query.rs
@@ -1,7 +1,5 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::implementation::{
-    Direction, Graph, NodeIndex, INCOMING, OUTGOING,
-};
+use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING};
 
 use super::{DepKind, DepNode};
 
@@ -52,23 +50,8 @@
         }
     }
 
-    /// All nodes reachable from `node`. In other words, things that
-    /// will have to be recomputed if `node` changes.
-    pub fn transitive_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
-        self.reachable_nodes(node, OUTGOING)
-    }
-
     /// All nodes that can reach `node`.
     pub fn transitive_predecessors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
         self.reachable_nodes(node, INCOMING)
     }
-
-    /// Just the outgoing edges from `node`.
-    pub fn immediate_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
-        if let Some(&index) = self.indices.get(&node) {
-            self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect()
-        } else {
-            vec![]
-        }
-    }
 }
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index 1839e1a..7bc6ae1 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -1,12 +1,12 @@
 use crate::dep_graph::DepNodeIndex;
 use crate::query::plumbing::{QueryLookup, QueryState};
-use crate::query::QueryContext;
 
 use rustc_arena::TypedArena;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sharded::Sharded;
 use rustc_data_structures::sync::WorkerLocal;
 use std::default::Default;
+use std::fmt::Debug;
 use std::hash::Hash;
 use std::marker::PhantomData;
 
@@ -24,16 +24,16 @@
 }
 
 pub trait QueryCache: QueryStorage {
-    type Key: Hash;
+    type Key: Hash + Eq + Clone + Debug;
     type Sharded: Default;
 
     /// Checks if the query is already computed and in the cache.
     /// It returns the shard index and a lock guard to the shard,
     /// which will be used if the query is not in the cache and we need
     /// to compute it.
-    fn lookup<CTX: QueryContext, R, OnHit, OnMiss>(
+    fn lookup<D, Q, R, OnHit, OnMiss>(
         &self,
-        state: &QueryState<CTX, Self>,
+        state: &QueryState<D, Q, Self>,
         key: Self::Key,
         // `on_hit` can be called while holding a lock to the query state shard.
         on_hit: OnHit,
@@ -41,7 +41,7 @@
     ) -> R
     where
         OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R,
-        OnMiss: FnOnce(Self::Key, QueryLookup<'_, CTX, Self::Key, Self::Sharded>) -> R;
+        OnMiss: FnOnce(Self::Key, QueryLookup<'_, D, Q, Self::Key, Self::Sharded>) -> R;
 
     fn complete(
         &self,
@@ -86,21 +86,25 @@
     }
 }
 
-impl<K: Eq + Hash, V: Clone> QueryCache for DefaultCache<K, V> {
+impl<K, V> QueryCache for DefaultCache<K, V>
+where
+    K: Eq + Hash + Clone + Debug,
+    V: Clone,
+{
     type Key = K;
     type Sharded = FxHashMap<K, (V, DepNodeIndex)>;
 
     #[inline(always)]
-    fn lookup<CTX: QueryContext, R, OnHit, OnMiss>(
+    fn lookup<D, Q, R, OnHit, OnMiss>(
         &self,
-        state: &QueryState<CTX, Self>,
+        state: &QueryState<D, Q, Self>,
         key: K,
         on_hit: OnHit,
         on_miss: OnMiss,
     ) -> R
     where
         OnHit: FnOnce(&V, DepNodeIndex) -> R,
-        OnMiss: FnOnce(K, QueryLookup<'_, CTX, K, Self::Sharded>) -> R,
+        OnMiss: FnOnce(K, QueryLookup<'_, D, Q, K, Self::Sharded>) -> R,
     {
         let mut lookup = state.get_lookup(&key);
         let lock = &mut *lookup.lock;
@@ -164,21 +168,24 @@
     }
 }
 
-impl<'tcx, K: Eq + Hash, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V> {
+impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V>
+where
+    K: Eq + Hash + Clone + Debug,
+{
     type Key = K;
     type Sharded = FxHashMap<K, &'tcx (V, DepNodeIndex)>;
 
     #[inline(always)]
-    fn lookup<CTX: QueryContext, R, OnHit, OnMiss>(
+    fn lookup<D, Q, R, OnHit, OnMiss>(
         &self,
-        state: &QueryState<CTX, Self>,
+        state: &QueryState<D, Q, Self>,
         key: K,
         on_hit: OnHit,
         on_miss: OnMiss,
     ) -> R
     where
         OnHit: FnOnce(&&'tcx V, DepNodeIndex) -> R,
-        OnMiss: FnOnce(K, QueryLookup<'_, CTX, K, Self::Sharded>) -> R,
+        OnMiss: FnOnce(K, QueryLookup<'_, D, Q, K, Self::Sharded>) -> R,
     {
         let mut lookup = state.get_lookup(&key);
         let lock = &mut *lookup.lock;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 5490565..6c9849e 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -12,9 +12,7 @@
 use std::fmt::Debug;
 use std::hash::Hash;
 
-// The parameter `CTX` is required in librustc_middle:
-// implementations may need to access the `'tcx` lifetime in `CTX = TyCtxt<'tcx>`.
-pub trait QueryConfig<CTX> {
+pub trait QueryConfig {
     const NAME: &'static str;
     const CATEGORY: ProfileCategory;
 
@@ -70,7 +68,7 @@
     }
 }
 
-pub trait QueryAccessors<CTX: QueryContext>: QueryConfig<CTX> {
+pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
     const ANON: bool;
     const EVAL_ALWAYS: bool;
     const DEP_KIND: CTX::DepKind;
@@ -78,7 +76,7 @@
     type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
 
     // Don't use this method to access query results, instead use the methods on TyCtxt
-    fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX, Self::Cache>;
+    fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, CTX::Query, Self::Cache>;
 
     fn to_dep_node(tcx: CTX, key: &Self::Key) -> DepNode<CTX::DepKind>
     where
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 190312b..c1d3210 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -1,16 +1,16 @@
-use crate::dep_graph::{DepContext, DepKind};
 use crate::query::plumbing::CycleError;
-use crate::query::QueryContext;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::Span;
 
 use std::convert::TryFrom;
+use std::hash::Hash;
 use std::marker::PhantomData;
 use std::num::NonZeroU32;
 
 #[cfg(parallel_compiler)]
 use {
+    super::QueryContext,
     parking_lot::{Condvar, Mutex},
     rustc_data_structures::fx::FxHashSet,
     rustc_data_structures::stable_hasher::{HashStable, StableHasher},
@@ -31,7 +31,7 @@
     pub query: Q,
 }
 
-type QueryMap<CTX> = FxHashMap<QueryJobId<<CTX as DepContext>::DepKind>, QueryJobInfo<CTX>>;
+pub(crate) type QueryMap<D, Q> = FxHashMap<QueryJobId<D>, QueryJobInfo<D, Q>>;
 
 /// A value uniquely identifiying an active query job within a shard in the query cache.
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
@@ -39,71 +39,75 @@
 
 /// A value uniquely identifiying an active query job.
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
-pub struct QueryJobId<K> {
+pub struct QueryJobId<D> {
     /// Which job within a shard is this
     pub job: QueryShardJobId,
 
     /// In which shard is this job
     pub shard: u16,
 
-    /// What kind of query this job is
-    pub kind: K,
+    /// What kind of query this job is.
+    pub kind: D,
 }
 
-impl<K: DepKind> QueryJobId<K> {
-    pub fn new(job: QueryShardJobId, shard: usize, kind: K) -> Self {
+impl<D> QueryJobId<D>
+where
+    D: Copy + Clone + Eq + Hash,
+{
+    pub fn new(job: QueryShardJobId, shard: usize, kind: D) -> Self {
         QueryJobId { job, shard: u16::try_from(shard).unwrap(), kind }
     }
 
-    fn query<CTX: QueryContext<DepKind = K>>(self, map: &QueryMap<CTX>) -> CTX::Query {
+    fn query<Q: Clone>(self, map: &QueryMap<D, Q>) -> Q {
         map.get(&self).unwrap().info.query.clone()
     }
 
     #[cfg(parallel_compiler)]
-    fn span<CTX: QueryContext<DepKind = K>>(self, map: &QueryMap<CTX>) -> Span {
+    fn span<Q: Clone>(self, map: &QueryMap<D, Q>) -> Span {
         map.get(&self).unwrap().job.span
     }
 
     #[cfg(parallel_compiler)]
-    fn parent<CTX: QueryContext<DepKind = K>>(self, map: &QueryMap<CTX>) -> Option<QueryJobId<K>> {
+    fn parent<Q: Clone>(self, map: &QueryMap<D, Q>) -> Option<QueryJobId<D>> {
         map.get(&self).unwrap().job.parent
     }
 
     #[cfg(parallel_compiler)]
-    fn latch<'a, CTX: QueryContext<DepKind = K>>(
-        self,
-        map: &'a QueryMap<CTX>,
-    ) -> Option<&'a QueryLatch<CTX>> {
+    fn latch<'a, Q: Clone>(self, map: &'a QueryMap<D, Q>) -> Option<&'a QueryLatch<D, Q>> {
         map.get(&self).unwrap().job.latch.as_ref()
     }
 }
 
-pub struct QueryJobInfo<CTX: QueryContext> {
-    pub info: QueryInfo<CTX::Query>,
-    pub job: QueryJob<CTX>,
+pub struct QueryJobInfo<D, Q> {
+    pub info: QueryInfo<Q>,
+    pub job: QueryJob<D, Q>,
 }
 
 /// Represents an active query job.
 #[derive(Clone)]
-pub struct QueryJob<CTX: QueryContext> {
+pub struct QueryJob<D, Q> {
     pub id: QueryShardJobId,
 
     /// The span corresponding to the reason for which this query was required.
     pub span: Span,
 
     /// The parent query job which created this job and is implicitly waiting on it.
-    pub parent: Option<QueryJobId<CTX::DepKind>>,
+    pub parent: Option<QueryJobId<D>>,
 
     /// The latch that is used to wait on this job.
     #[cfg(parallel_compiler)]
-    latch: Option<QueryLatch<CTX>>,
+    latch: Option<QueryLatch<D, Q>>,
 
-    dummy: PhantomData<QueryLatch<CTX>>,
+    dummy: PhantomData<QueryLatch<D, Q>>,
 }
 
-impl<CTX: QueryContext> QueryJob<CTX> {
+impl<D, Q> QueryJob<D, Q>
+where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+{
     /// Creates a new query job.
-    pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId<CTX::DepKind>>) -> Self {
+    pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId<D>>) -> Self {
         QueryJob {
             id,
             span,
@@ -115,7 +119,7 @@
     }
 
     #[cfg(parallel_compiler)]
-    pub(super) fn latch(&mut self, _id: QueryJobId<CTX::DepKind>) -> QueryLatch<CTX> {
+    pub(super) fn latch(&mut self, _id: QueryJobId<D>) -> QueryLatch<D, Q> {
         if self.latch.is_none() {
             self.latch = Some(QueryLatch::new());
         }
@@ -123,7 +127,7 @@
     }
 
     #[cfg(not(parallel_compiler))]
-    pub(super) fn latch(&mut self, id: QueryJobId<CTX::DepKind>) -> QueryLatch<CTX> {
+    pub(super) fn latch(&mut self, id: QueryJobId<D>) -> QueryLatch<D, Q> {
         QueryLatch { id, dummy: PhantomData }
     }
 
@@ -143,19 +147,26 @@
 
 #[cfg(not(parallel_compiler))]
 #[derive(Clone)]
-pub(super) struct QueryLatch<CTX: QueryContext> {
-    id: QueryJobId<CTX::DepKind>,
-    dummy: PhantomData<CTX>,
+pub(super) struct QueryLatch<D, Q> {
+    id: QueryJobId<D>,
+    dummy: PhantomData<Q>,
 }
 
 #[cfg(not(parallel_compiler))]
-impl<CTX: QueryContext> QueryLatch<CTX> {
-    pub(super) fn find_cycle_in_stack(&self, tcx: CTX, span: Span) -> CycleError<CTX::Query> {
-        let query_map = tcx.try_collect_active_jobs().unwrap();
-
-        // Get the current executing query (waiter) and find the waitee amongst its parents
-        let mut current_job = tcx.current_query_job();
+impl<D, Q> QueryLatch<D, Q>
+where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+{
+    pub(super) fn find_cycle_in_stack(
+        &self,
+        query_map: QueryMap<D, Q>,
+        current_job: &Option<QueryJobId<D>>,
+        span: Span,
+    ) -> CycleError<Q> {
+        // Find the waitee amongst `current_job` parents
         let mut cycle = Vec::new();
+        let mut current_job = Option::clone(current_job);
 
         while let Some(job) = current_job {
             let info = query_map.get(&job).unwrap();
@@ -186,15 +197,15 @@
 }
 
 #[cfg(parallel_compiler)]
-struct QueryWaiter<CTX: QueryContext> {
-    query: Option<QueryJobId<CTX::DepKind>>,
+struct QueryWaiter<D, Q> {
+    query: Option<QueryJobId<D>>,
     condvar: Condvar,
     span: Span,
-    cycle: Lock<Option<CycleError<CTX::Query>>>,
+    cycle: Lock<Option<CycleError<Q>>>,
 }
 
 #[cfg(parallel_compiler)]
-impl<CTX: QueryContext> QueryWaiter<CTX> {
+impl<D, Q> QueryWaiter<D, Q> {
     fn notify(&self, registry: &rayon_core::Registry) {
         rayon_core::mark_unblocked(registry);
         self.condvar.notify_one();
@@ -202,19 +213,19 @@
 }
 
 #[cfg(parallel_compiler)]
-struct QueryLatchInfo<CTX: QueryContext> {
+struct QueryLatchInfo<D, Q> {
     complete: bool,
-    waiters: Vec<Lrc<QueryWaiter<CTX>>>,
+    waiters: Vec<Lrc<QueryWaiter<D, Q>>>,
 }
 
 #[cfg(parallel_compiler)]
 #[derive(Clone)]
-pub(super) struct QueryLatch<CTX: QueryContext> {
-    info: Lrc<Mutex<QueryLatchInfo<CTX>>>,
+pub(super) struct QueryLatch<D, Q> {
+    info: Lrc<Mutex<QueryLatchInfo<D, Q>>>,
 }
 
 #[cfg(parallel_compiler)]
-impl<CTX: QueryContext> QueryLatch<CTX> {
+impl<D: Eq + Hash, Q: Clone> QueryLatch<D, Q> {
     fn new() -> Self {
         QueryLatch {
             info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
@@ -223,10 +234,13 @@
 }
 
 #[cfg(parallel_compiler)]
-impl<CTX: QueryContext> QueryLatch<CTX> {
+impl<D, Q> QueryLatch<D, Q> {
     /// Awaits for the query job to complete.
-    pub(super) fn wait_on(&self, tcx: CTX, span: Span) -> Result<(), CycleError<CTX::Query>> {
-        let query = tcx.current_query_job();
+    pub(super) fn wait_on(
+        &self,
+        query: Option<QueryJobId<D>>,
+        span: Span,
+    ) -> Result<(), CycleError<Q>> {
         let waiter =
             Lrc::new(QueryWaiter { query, span, cycle: Lock::new(None), condvar: Condvar::new() });
         self.wait_on_inner(&waiter);
@@ -239,12 +253,9 @@
             Some(cycle) => Err(cycle),
         }
     }
-}
 
-#[cfg(parallel_compiler)]
-impl<CTX: QueryContext> QueryLatch<CTX> {
     /// Awaits the caller on this latch by blocking the current thread.
-    fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<CTX>>) {
+    fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<D, Q>>) {
         let mut info = self.info.lock();
         if !info.complete {
             // We push the waiter on to the `waiters` list. It can be accessed inside
@@ -278,7 +289,7 @@
 
     /// Removes a single waiter from the list of waiters.
     /// This is used to break query cycles.
-    fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<CTX>> {
+    fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<D, Q>> {
         let mut info = self.info.lock();
         debug_assert!(!info.complete);
         // Remove the waiter from the list of waiters
@@ -288,7 +299,7 @@
 
 /// A resumable waiter of a query. The usize is the index into waiters in the query's latch
 #[cfg(parallel_compiler)]
-type Waiter<K> = (QueryJobId<K>, usize);
+type Waiter<D> = (QueryJobId<D>, usize);
 
 /// Visits all the non-resumable and resumable waiters of a query.
 /// Only waiters in a query are visited.
@@ -300,13 +311,15 @@
 /// required information to resume the waiter.
 /// If all `visit` calls returns None, this function also returns None.
 #[cfg(parallel_compiler)]
-fn visit_waiters<CTX: QueryContext, F>(
-    query_map: &QueryMap<CTX>,
-    query: QueryJobId<CTX::DepKind>,
+fn visit_waiters<D, Q, F>(
+    query_map: &QueryMap<D, Q>,
+    query: QueryJobId<D>,
     mut visit: F,
-) -> Option<Option<Waiter<CTX::DepKind>>>
+) -> Option<Option<Waiter<D>>>
 where
-    F: FnMut(Span, QueryJobId<CTX::DepKind>) -> Option<Option<Waiter<CTX::DepKind>>>,
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+    F: FnMut(Span, QueryJobId<D>) -> Option<Option<Waiter<D>>>,
 {
     // Visit the parent query which is a non-resumable waiter since it's on the same stack
     if let Some(parent) = query.parent(query_map) {
@@ -335,13 +348,17 @@
 /// If a cycle is detected, this initial value is replaced with the span causing
 /// the cycle.
 #[cfg(parallel_compiler)]
-fn cycle_check<CTX: QueryContext>(
-    query_map: &QueryMap<CTX>,
-    query: QueryJobId<CTX::DepKind>,
+fn cycle_check<D, Q>(
+    query_map: &QueryMap<D, Q>,
+    query: QueryJobId<D>,
     span: Span,
-    stack: &mut Vec<(Span, QueryJobId<CTX::DepKind>)>,
-    visited: &mut FxHashSet<QueryJobId<CTX::DepKind>>,
-) -> Option<Option<Waiter<CTX::DepKind>>> {
+    stack: &mut Vec<(Span, QueryJobId<D>)>,
+    visited: &mut FxHashSet<QueryJobId<D>>,
+) -> Option<Option<Waiter<D>>>
+where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+{
     if !visited.insert(query) {
         return if let Some(p) = stack.iter().position(|q| q.1 == query) {
             // We detected a query cycle, fix up the initial span and return Some
@@ -376,11 +393,15 @@
 /// from `query` without going through any of the queries in `visited`.
 /// This is achieved with a depth first search.
 #[cfg(parallel_compiler)]
-fn connected_to_root<CTX: QueryContext>(
-    query_map: &QueryMap<CTX>,
-    query: QueryJobId<CTX::DepKind>,
-    visited: &mut FxHashSet<QueryJobId<CTX::DepKind>>,
-) -> bool {
+fn connected_to_root<D, Q>(
+    query_map: &QueryMap<D, Q>,
+    query: QueryJobId<D>,
+    visited: &mut FxHashSet<QueryJobId<D>>,
+) -> bool
+where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+{
     // We already visited this or we're deliberately ignoring it
     if !visited.insert(query) {
         return false;
@@ -399,7 +420,12 @@
 
 // Deterministically pick an query from a list
 #[cfg(parallel_compiler)]
-fn pick_query<'a, CTX, T, F>(query_map: &QueryMap<CTX>, tcx: CTX, queries: &'a [T], f: F) -> &'a T
+fn pick_query<'a, CTX, T, F>(
+    query_map: &QueryMap<CTX::DepKind, CTX::Query>,
+    tcx: CTX,
+    queries: &'a [T],
+    f: F,
+) -> &'a T
 where
     CTX: QueryContext,
     F: Fn(&T) -> (Span, QueryJobId<CTX::DepKind>),
@@ -429,9 +455,9 @@
 /// the function returns false.
 #[cfg(parallel_compiler)]
 fn remove_cycle<CTX: QueryContext>(
-    query_map: &QueryMap<CTX>,
+    query_map: &QueryMap<CTX::DepKind, CTX::Query>,
     jobs: &mut Vec<QueryJobId<CTX::DepKind>>,
-    wakelist: &mut Vec<Lrc<QueryWaiter<CTX>>>,
+    wakelist: &mut Vec<Lrc<QueryWaiter<CTX::DepKind, CTX::Query>>>,
     tcx: CTX,
 ) -> bool {
     let mut visited = FxHashSet::default();
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 4909772..da45565 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -15,8 +15,8 @@
 pub use self::config::{QueryAccessors, QueryConfig, QueryDescription};
 
 use crate::dep_graph::{DepContext, DepGraph};
+use crate::query::job::QueryMap;
 
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::HashStable;
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
@@ -38,9 +38,7 @@
     /// Get the query information from the TLS context.
     fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
 
-    fn try_collect_active_jobs(
-        &self,
-    ) -> Option<FxHashMap<QueryJobId<Self::DepKind>, QueryJobInfo<Self>>>;
+    fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind, Self::Query>>;
 
     /// Executes a job by changing the `ImplicitCtxt` to point to the
     /// new query job while it executes. It returns the diagnostics
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index ae042cc..50f4437 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -7,7 +7,7 @@
 use crate::query::caches::QueryCache;
 use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
 use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId};
-use crate::query::QueryContext;
+use crate::query::{QueryContext, QueryMap};
 
 #[cfg(not(parallel_compiler))]
 use rustc_data_structures::cold_path;
@@ -20,8 +20,6 @@
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::Span;
 use std::collections::hash_map::Entry;
-use std::convert::TryFrom;
-use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::num::NonZeroU32;
@@ -29,33 +27,33 @@
 #[cfg(debug_assertions)]
 use std::sync::atomic::{AtomicUsize, Ordering};
 
-pub(super) struct QueryStateShard<CTX: QueryContext, K, C> {
+pub(super) struct QueryStateShard<D, Q, K, C> {
     pub(super) cache: C,
-    active: FxHashMap<K, QueryResult<CTX>>,
+    active: FxHashMap<K, QueryResult<D, Q>>,
 
     /// Used to generate unique ids for active jobs.
     jobs: u32,
 }
 
-impl<CTX: QueryContext, K, C: Default> Default for QueryStateShard<CTX, K, C> {
-    fn default() -> QueryStateShard<CTX, K, C> {
+impl<D, Q, K, C: Default> Default for QueryStateShard<D, Q, K, C> {
+    fn default() -> QueryStateShard<D, Q, K, C> {
         QueryStateShard { cache: Default::default(), active: Default::default(), jobs: 0 }
     }
 }
 
-pub struct QueryState<CTX: QueryContext, C: QueryCache> {
+pub struct QueryState<D, Q, C: QueryCache> {
     cache: C,
-    shards: Sharded<QueryStateShard<CTX, C::Key, C::Sharded>>,
+    shards: Sharded<QueryStateShard<D, Q, C::Key, C::Sharded>>,
     #[cfg(debug_assertions)]
     pub cache_hits: AtomicUsize,
 }
 
-impl<CTX: QueryContext, C: QueryCache> QueryState<CTX, C> {
+impl<D, Q, C: QueryCache> QueryState<D, Q, C> {
     #[inline]
     pub(super) fn get_lookup<'tcx>(
         &'tcx self,
         key: &C::Key,
-    ) -> QueryLookup<'tcx, CTX, C::Key, C::Sharded> {
+    ) -> QueryLookup<'tcx, D, Q, C::Key, C::Sharded> {
         // We compute the key's hash once and then use it for both the
         // shard lookup and the hashmap lookup. This relies on the fact
         // that both of them use `FxHasher`.
@@ -70,16 +68,21 @@
 }
 
 /// Indicates the state of a query for a given key in a query map.
-enum QueryResult<CTX: QueryContext> {
+enum QueryResult<D, Q> {
     /// An already executing query. The query job can be used to await for its completion.
-    Started(QueryJob<CTX>),
+    Started(QueryJob<D, Q>),
 
     /// The query panicked. Queries trying to wait on this will raise a fatal error which will
     /// silently panic.
     Poisoned,
 }
 
-impl<CTX: QueryContext, C: QueryCache> QueryState<CTX, C> {
+impl<D, Q, C> QueryState<D, Q, C>
+where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+    C: QueryCache,
+{
     #[inline(always)]
     pub fn iter_results<R>(
         &self,
@@ -98,13 +101,10 @@
 
     pub fn try_collect_active_jobs(
         &self,
-        kind: CTX::DepKind,
-        make_query: fn(C::Key) -> CTX::Query,
-        jobs: &mut FxHashMap<QueryJobId<CTX::DepKind>, QueryJobInfo<CTX>>,
-    ) -> Option<()>
-    where
-        C::Key: Clone,
-    {
+        kind: D,
+        make_query: fn(C::Key) -> Q,
+        jobs: &mut QueryMap<D, Q>,
+    ) -> Option<()> {
         // We use try_lock_shards here since we are called from the
         // deadlock handler, and this shouldn't be locked.
         let shards = self.shards.try_lock_shards()?;
@@ -112,8 +112,7 @@
         jobs.extend(shards.flat_map(|(shard_id, shard)| {
             shard.active.iter().filter_map(move |(k, v)| {
                 if let QueryResult::Started(ref job) = *v {
-                    let id =
-                        QueryJobId { job: job.id, shard: u16::try_from(shard_id).unwrap(), kind };
+                    let id = QueryJobId::new(job.id, shard_id, kind);
                     let info = QueryInfo { span: job.span, query: make_query(k.clone()) };
                     Some((id, QueryJobInfo { info, job: job.clone() }))
                 } else {
@@ -126,8 +125,8 @@
     }
 }
 
-impl<CTX: QueryContext, C: QueryCache> Default for QueryState<CTX, C> {
-    fn default() -> QueryState<CTX, C> {
+impl<D, Q, C: QueryCache> Default for QueryState<D, Q, C> {
+    fn default() -> QueryState<D, Q, C> {
         QueryState {
             cache: C::default(),
             shards: Default::default(),
@@ -138,28 +137,30 @@
 }
 
 /// Values used when checking a query cache which can be reused on a cache-miss to execute the query.
-pub struct QueryLookup<'tcx, CTX: QueryContext, K, C> {
+pub struct QueryLookup<'tcx, D, Q, K, C> {
     pub(super) key_hash: u64,
     shard: usize,
-    pub(super) lock: LockGuard<'tcx, QueryStateShard<CTX, K, C>>,
+    pub(super) lock: LockGuard<'tcx, QueryStateShard<D, Q, K, C>>,
 }
 
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
-struct JobOwner<'tcx, CTX: QueryContext, C>
+struct JobOwner<'tcx, D, Q, C>
 where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
     C: QueryCache,
-    C::Key: Eq + Hash + Clone + Debug,
 {
-    state: &'tcx QueryState<CTX, C>,
+    state: &'tcx QueryState<D, Q, C>,
     key: C::Key,
-    id: QueryJobId<CTX::DepKind>,
+    id: QueryJobId<D>,
 }
 
-impl<'tcx, CTX: QueryContext, C> JobOwner<'tcx, CTX, C>
+impl<'tcx, D, Q, C> JobOwner<'tcx, D, Q, C>
 where
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
     C: QueryCache,
-    C::Key: Eq + Hash + Clone + Debug,
 {
     /// Either gets a `JobOwner` corresponding the query, allowing us to
     /// start executing the query, or returns with the result of the query.
@@ -170,14 +171,14 @@
     /// This function is inlined because that results in a noticeable speed-up
     /// for some compile-time benchmarks.
     #[inline(always)]
-    fn try_start<'a, 'b>(
+    fn try_start<'a, 'b, CTX>(
         tcx: CTX,
-        state: &'b QueryState<CTX, C>,
+        state: &'b QueryState<CTX::DepKind, CTX::Query, C>,
         span: Span,
         key: &C::Key,
-        mut lookup: QueryLookup<'a, CTX, C::Key, C::Sharded>,
+        mut lookup: QueryLookup<'a, CTX::DepKind, CTX::Query, C::Key, C::Sharded>,
         query: &QueryVtable<CTX, C::Key, C::Value>,
-    ) -> TryGetJob<'b, CTX, C>
+    ) -> TryGetJob<'b, CTX::DepKind, CTX::Query, C>
     where
         CTX: QueryContext,
     {
@@ -229,7 +230,12 @@
         // so we just return the error.
         #[cfg(not(parallel_compiler))]
         return TryGetJob::Cycle(cold_path(|| {
-            let value = query.handle_cycle_error(tcx, latch.find_cycle_in_stack(tcx, span));
+            let error: CycleError<CTX::Query> = latch.find_cycle_in_stack(
+                tcx.try_collect_active_jobs().unwrap(),
+                &tcx.current_query_job(),
+                span,
+            );
+            let value = query.handle_cycle_error(tcx, error);
             state.cache.store_nocache(value)
         }));
 
@@ -237,7 +243,7 @@
         // thread.
         #[cfg(parallel_compiler)]
         {
-            let result = latch.wait_on(tcx, span);
+            let result = latch.wait_on(tcx.current_query_job(), span);
 
             if let Err(cycle) = result {
                 let value = query.handle_cycle_error(tcx, cycle);
@@ -297,9 +303,11 @@
     (result, diagnostics.into_inner())
 }
 
-impl<'tcx, CTX: QueryContext, C: QueryCache> Drop for JobOwner<'tcx, CTX, C>
+impl<'tcx, D, Q, C> Drop for JobOwner<'tcx, D, Q, C>
 where
-    C::Key: Eq + Hash + Clone + Debug,
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+    C: QueryCache,
 {
     #[inline(never)]
     #[cold]
@@ -330,12 +338,14 @@
 }
 
 /// The result of `try_start`.
-enum TryGetJob<'tcx, CTX: QueryContext, C: QueryCache>
+enum TryGetJob<'tcx, D, Q, C>
 where
-    C::Key: Eq + Hash + Clone + Debug,
+    D: Copy + Clone + Eq + Hash,
+    Q: Clone,
+    C: QueryCache,
 {
     /// The query is not yet started. Contains a guard to the cache eventually used to start it.
-    NotYetStarted(JobOwner<'tcx, CTX, C>),
+    NotYetStarted(JobOwner<'tcx, D, Q, C>),
 
     /// The query was already completed.
     /// Returns the result of the query and its dep-node index
@@ -354,7 +364,7 @@
 #[inline(always)]
 fn try_get_cached<CTX, C, R, OnHit, OnMiss>(
     tcx: CTX,
-    state: &QueryState<CTX, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C>,
     key: C::Key,
     // `on_hit` can be called while holding a lock to the query cache
     on_hit: OnHit,
@@ -364,7 +374,7 @@
     C: QueryCache,
     CTX: QueryContext,
     OnHit: FnOnce(&C::Stored, DepNodeIndex) -> R,
-    OnMiss: FnOnce(C::Key, QueryLookup<'_, CTX, C::Key, C::Sharded>) -> R,
+    OnMiss: FnOnce(C::Key, QueryLookup<'_, CTX::DepKind, CTX::Query, C::Key, C::Sharded>) -> R,
 {
     state.cache.lookup(
         state,
@@ -386,19 +396,20 @@
 #[inline(always)]
 fn try_execute_query<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C>,
     span: Span,
     key: C::Key,
-    lookup: QueryLookup<'_, CTX, C::Key, C::Sharded>,
+    lookup: QueryLookup<'_, CTX::DepKind, CTX::Query, C::Key, C::Sharded>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
 ) -> C::Stored
 where
     C: QueryCache,
-    C::Key: Eq + Clone + Debug + crate::dep_graph::DepNodeParams<CTX>,
-    C::Stored: Clone,
+    C::Key: crate::dep_graph::DepNodeParams<CTX>,
     CTX: QueryContext,
 {
-    let job = match JobOwner::try_start(tcx, state, span, &key, lookup, query) {
+    let job = match JobOwner::<'_, CTX::DepKind, CTX::Query, C>::try_start(
+        tcx, state, span, &key, lookup, query,
+    ) {
         TryGetJob::NotYetStarted(job) => job,
         TryGetJob::Cycle(result) => return result,
         #[cfg(parallel_compiler)]
@@ -559,14 +570,12 @@
 fn force_query_with_job<C, CTX>(
     tcx: CTX,
     key: C::Key,
-    job: JobOwner<'_, CTX, C>,
+    job: JobOwner<'_, CTX::DepKind, CTX::Query, C>,
     dep_node: DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
 ) -> (C::Stored, DepNodeIndex)
 where
     C: QueryCache,
-    C::Key: Eq + Clone + Debug,
-    C::Stored: Clone,
     CTX: QueryContext,
 {
     // If the following assertion triggers, it can have two reasons:
@@ -617,7 +626,7 @@
 #[inline(never)]
 fn get_query_impl<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C>,
     span: Span,
     key: C::Key,
     query: &QueryVtable<CTX, C::Key, C::Value>,
@@ -625,8 +634,7 @@
 where
     CTX: QueryContext,
     C: QueryCache,
-    C::Key: Eq + Clone + crate::dep_graph::DepNodeParams<CTX>,
-    C::Stored: Clone,
+    C::Key: crate::dep_graph::DepNodeParams<CTX>,
 {
     try_get_cached(
         tcx,
@@ -650,12 +658,12 @@
 #[inline(never)]
 fn ensure_query_impl<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C>,
     key: C::Key,
     query: &QueryVtable<CTX, C::Key, C::Value>,
 ) where
     C: QueryCache,
-    C::Key: Eq + Clone + crate::dep_graph::DepNodeParams<CTX>,
+    C::Key: crate::dep_graph::DepNodeParams<CTX>,
     CTX: QueryContext,
 {
     if query.eval_always {
@@ -687,14 +695,14 @@
 #[inline(never)]
 fn force_query_impl<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C>,
     key: C::Key,
     span: Span,
     dep_node: DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
 ) where
     C: QueryCache,
-    C::Key: Eq + Clone + crate::dep_graph::DepNodeParams<CTX>,
+    C::Key: crate::dep_graph::DepNodeParams<CTX>,
     CTX: QueryContext,
 {
     // We may be concurrently trying both execute and force a query.
@@ -708,7 +716,9 @@
             // Cache hit, do nothing
         },
         |key, lookup| {
-            let job = match JobOwner::try_start(tcx, state, span, &key, lookup, query) {
+            let job = match JobOwner::<'_, CTX::DepKind, CTX::Query, C>::try_start(
+                tcx, state, span, &key, lookup, query,
+            ) {
                 TryGetJob::NotYetStarted(job) => job,
                 TryGetJob::Cycle(_) => return,
                 #[cfg(parallel_compiler)]
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index a48d002..02e31ad 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -613,12 +613,21 @@
 
     /// Constructs the reduced graph for one item.
     fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
+        if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Invalid {
+            // Fake crate root item from expand.
+            return;
+        }
+
         let parent_scope = &self.parent_scope;
         let parent = parent_scope.module;
         let expansion = parent_scope.expansion;
         let ident = item.ident;
         let sp = item.span;
         let vis = self.resolve_visibility(&item.vis);
+        let local_def_id = self.r.local_def_id(item.id);
+        let def_id = local_def_id.to_def_id();
+
+        self.r.visibilities.insert(local_def_id, vis);
 
         match item.kind {
             ItemKind::Use(ref use_tree) => {
@@ -651,10 +660,12 @@
                 } else if orig_name == Some(kw::SelfLower) {
                     self.r.graph_root
                 } else {
-                    let def_id = self.r.local_def_id(item.id);
-                    let crate_id =
-                        self.r.crate_loader.process_extern_crate(item, &self.r.definitions, def_id);
-                    self.r.extern_crate_map.insert(def_id, crate_id);
+                    let crate_id = self.r.crate_loader.process_extern_crate(
+                        item,
+                        &self.r.definitions,
+                        local_def_id,
+                    );
+                    self.r.extern_crate_map.insert(local_def_id, crate_id);
                     self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
                 };
 
@@ -705,25 +716,16 @@
                 self.r.define(parent, ident, TypeNS, imported_binding);
             }
 
-            ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
-
             ItemKind::Mod(..) => {
-                let def_id = self.r.local_def_id(item.id);
-                let module_kind = ModuleKind::Def(DefKind::Mod, def_id.to_def_id(), ident.name);
+                let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name);
                 let module = self.r.arenas.alloc_module(ModuleData {
                     no_implicit_prelude: parent.no_implicit_prelude || {
                         self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude)
                     },
-                    ..ModuleData::new(
-                        Some(parent),
-                        module_kind,
-                        def_id.to_def_id(),
-                        expansion,
-                        item.span,
-                    )
+                    ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span)
                 });
                 self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
-                self.r.module_map.insert(def_id, module);
+                self.r.module_map.insert(local_def_id, module);
 
                 // Descend into the module.
                 self.parent_scope.module = module;
@@ -731,15 +733,15 @@
 
             // These items live in the value namespace.
             ItemKind::Static(..) => {
-                let res = Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Static, def_id);
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Const(..) => {
-                let res = Res::Def(DefKind::Const, self.r.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Const, def_id);
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
             }
             ItemKind::Fn(..) => {
-                let res = Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::Fn, def_id);
                 self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion));
 
                 // Functions introducing procedural macros reserve a slot
@@ -749,13 +751,11 @@
 
             // These items live in the type namespace.
             ItemKind::TyAlias(..) => {
-                let res = Res::Def(DefKind::TyAlias, self.r.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::TyAlias, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             ItemKind::Enum(_, _) => {
-                let def_id = self.r.local_def_id(item.id).to_def_id();
-                self.r.variant_vis.insert(def_id, vis);
                 let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name);
                 let module = self.r.new_module(
                     parent,
@@ -769,14 +769,13 @@
             }
 
             ItemKind::TraitAlias(..) => {
-                let res = Res::Def(DefKind::TraitAlias, self.r.local_def_id(item.id).to_def_id());
+                let res = Res::Def(DefKind::TraitAlias, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
             }
 
             // These items live in both the type and value namespaces.
             ItemKind::Struct(ref vdata, _) => {
                 // Define a name in the type namespace.
-                let def_id = self.r.local_def_id(item.id).to_def_id();
                 let res = Res::Def(DefKind::Struct, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
@@ -810,17 +809,19 @@
                         }
                         ret_fields.push(field_vis);
                     }
+                    let ctor_def_id = self.r.local_def_id(ctor_node_id);
                     let ctor_res = Res::Def(
                         DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
-                        self.r.local_def_id(ctor_node_id).to_def_id(),
+                        ctor_def_id.to_def_id(),
                     );
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
+                    self.r.visibilities.insert(ctor_def_id, ctor_vis);
+
                     self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields));
                 }
             }
 
             ItemKind::Union(ref vdata, _) => {
-                let def_id = self.r.local_def_id(item.id).to_def_id();
                 let res = Res::Def(DefKind::Union, def_id);
                 self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
 
@@ -829,8 +830,6 @@
             }
 
             ItemKind::Trait(..) => {
-                let def_id = self.r.local_def_id(item.id).to_def_id();
-
                 // Add all the items within to a new module.
                 let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name);
                 let module = self.r.new_module(
@@ -845,6 +844,9 @@
             }
 
             // These items do not add names to modules.
+            ItemKind::Impl { of_trait: Some(..), .. } => {
+                self.r.trait_impl_items.insert(local_def_id);
+            }
             ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
 
             ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(),
@@ -853,22 +855,20 @@
 
     /// Constructs the reduced graph for one foreign item.
     fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
-        let (res, ns) = match item.kind {
-            ForeignItemKind::Fn(..) => {
-                (Res::Def(DefKind::Fn, self.r.local_def_id(item.id).to_def_id()), ValueNS)
-            }
-            ForeignItemKind::Static(..) => {
-                (Res::Def(DefKind::Static, self.r.local_def_id(item.id).to_def_id()), ValueNS)
-            }
-            ForeignItemKind::TyAlias(..) => {
-                (Res::Def(DefKind::ForeignTy, self.r.local_def_id(item.id).to_def_id()), TypeNS)
-            }
+        let local_def_id = self.r.local_def_id(item.id);
+        let def_id = local_def_id.to_def_id();
+        let (def_kind, ns) = match item.kind {
+            ForeignItemKind::Fn(..) => (DefKind::Fn, ValueNS),
+            ForeignItemKind::Static(..) => (DefKind::Static, ValueNS),
+            ForeignItemKind::TyAlias(..) => (DefKind::ForeignTy, TypeNS),
             ForeignItemKind::MacCall(_) => unreachable!(),
         };
         let parent = self.parent_scope.module;
         let expansion = self.parent_scope.expansion;
         let vis = self.resolve_visibility(&item.vis);
+        let res = Res::Def(def_kind, def_id);
         self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
+        self.r.visibilities.insert(local_def_id, vis);
     }
 
     fn build_reduced_graph_for_block(&mut self, block: &Block) {
@@ -1205,6 +1205,7 @@
                 self.r.check_reserved_macro_name(ident, res);
                 self.insert_unused_macro(ident, def_id, item.id, span);
             }
+            self.r.visibilities.insert(def_id, vis);
             MacroRulesScope::Binding(self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding {
                 parent_macro_rules_scope: parent_scope.macro_rules,
                 binding,
@@ -1224,6 +1225,7 @@
                 self.insert_unused_macro(ident, def_id, item.id, span);
             }
             self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
+            self.r.visibilities.insert(def_id, vis);
             self.parent_scope.macro_rules
         }
     }
@@ -1297,36 +1299,64 @@
     }
 
     fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
-        let parent = self.parent_scope.module;
-
         if let AssocItemKind::MacCall(_) = item.kind {
             self.visit_invoc(item.id);
             return;
         }
 
-        if let AssocCtxt::Impl = ctxt {
-            self.resolve_visibility(&item.vis);
-            visit::walk_assoc_item(self, item, ctxt);
-            return;
-        }
+        let local_def_id = self.r.local_def_id(item.id);
+        let def_id = local_def_id.to_def_id();
+        let vis = match ctxt {
+            AssocCtxt::Trait => {
+                let (def_kind, ns) = match item.kind {
+                    AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
+                    AssocItemKind::Fn(_, ref sig, _, _) => {
+                        if sig.decl.has_self() {
+                            self.r.has_self.insert(def_id);
+                        }
+                        (DefKind::AssocFn, ValueNS)
+                    }
+                    AssocItemKind::TyAlias(..) => (DefKind::AssocTy, TypeNS),
+                    AssocItemKind::MacCall(_) => bug!(), // handled above
+                };
 
-        // Add the item to the trait info.
-        let item_def_id = self.r.local_def_id(item.id).to_def_id();
-        let (res, ns) = match item.kind {
-            AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
-            AssocItemKind::Fn(_, ref sig, _, _) => {
-                if sig.decl.has_self() {
-                    self.r.has_self.insert(item_def_id);
-                }
-                (Res::Def(DefKind::AssocFn, item_def_id), ValueNS)
+                let parent = self.parent_scope.module;
+                let expansion = self.parent_scope.expansion;
+                let res = Res::Def(def_kind, def_id);
+                // Trait item visibility is inherited from its trait when not specified explicitly.
+                let vis = match &item.vis.kind {
+                    ast::VisibilityKind::Inherited => {
+                        self.r.visibilities[&parent.def_id().unwrap().expect_local()]
+                    }
+                    _ => self.resolve_visibility(&item.vis),
+                };
+                // FIXME: For historical reasons the binding visibility is set to public,
+                // use actual visibility here instead, using enum variants as an example.
+                let vis_hack = ty::Visibility::Public;
+                self.r.define(parent, item.ident, ns, (res, vis_hack, item.span, expansion));
+                Some(vis)
             }
-            AssocItemKind::TyAlias(..) => (Res::Def(DefKind::AssocTy, item_def_id), TypeNS),
-            AssocItemKind::MacCall(_) => bug!(), // handled above
+            AssocCtxt::Impl => {
+                // Trait impl item visibility is inherited from its trait when not specified
+                // explicitly. In that case we cannot determine it here in early resolve,
+                // so we leave a hole in the visibility table to be filled later.
+                // Inherent impl item visibility is never inherited from other items.
+                if matches!(item.vis.kind, ast::VisibilityKind::Inherited)
+                    && self
+                        .r
+                        .trait_impl_items
+                        .contains(&ty::DefIdTree::parent(&*self.r, def_id).unwrap().expect_local())
+                {
+                    None
+                } else {
+                    Some(self.resolve_visibility(&item.vis))
+                }
+            }
         };
 
-        let vis = ty::Visibility::Public;
-        let expansion = self.parent_scope.expansion;
-        self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
+        if let Some(vis) = vis {
+            self.r.visibilities.insert(local_def_id, vis);
+        }
 
         visit::walk_assoc_item(self, item, ctxt);
     }
@@ -1394,7 +1424,8 @@
         if sf.is_placeholder {
             self.visit_invoc(sf.id);
         } else {
-            self.resolve_visibility(&sf.vis);
+            let vis = self.resolve_visibility(&sf.vis);
+            self.r.visibilities.insert(self.r.local_def_id(sf.id), vis);
             visit::walk_struct_field(self, sf);
         }
     }
@@ -1408,22 +1439,30 @@
         }
 
         let parent = self.parent_scope.module;
-        let vis = self.r.variant_vis[&parent.def_id().expect("enum without def-id")];
+        let vis = match variant.vis.kind {
+            // Variant visibility is inherited from its enum when not specified explicitly.
+            ast::VisibilityKind::Inherited => {
+                self.r.visibilities[&parent.def_id().unwrap().expect_local()]
+            }
+            _ => self.resolve_visibility(&variant.vis),
+        };
         let expn_id = self.parent_scope.expansion;
         let ident = variant.ident;
 
         // Define a name in the type namespace.
-        let def_id = self.r.local_def_id(variant.id).to_def_id();
-        let res = Res::Def(DefKind::Variant, def_id);
+        let def_id = self.r.local_def_id(variant.id);
+        let res = Res::Def(DefKind::Variant, def_id.to_def_id());
         self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
+        self.r.visibilities.insert(def_id, vis);
 
-        // If the variant is marked as non_exhaustive then lower the visibility to within the
-        // crate.
-        let mut ctor_vis = vis;
-        let has_non_exhaustive = self.r.session.contains_name(&variant.attrs, sym::non_exhaustive);
-        if has_non_exhaustive && vis == ty::Visibility::Public {
-            ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-        }
+        // If the variant is marked as non_exhaustive then lower the visibility to within the crate.
+        let ctor_vis = if vis == ty::Visibility::Public
+            && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
+        {
+            ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+        } else {
+            vis
+        };
 
         // Define a constructor name in the value namespace.
         // Braced variants, unlike structs, generate unusable names in
@@ -1431,12 +1470,15 @@
         // It's ok to use the variant's id as a ctor id since an
         // error will be reported on any use of such resolution anyway.
         let ctor_node_id = variant.data.ctor_id().unwrap_or(variant.id);
-        let ctor_def_id = self.r.local_def_id(ctor_node_id).to_def_id();
+        let ctor_def_id = self.r.local_def_id(ctor_node_id);
         let ctor_kind = CtorKind::from_ast(&variant.data);
-        let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
+        let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id.to_def_id());
         self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
+        if ctor_def_id != def_id {
+            self.r.visibilities.insert(ctor_def_id, ctor_vis);
+        }
         // Record field names for error reporting.
-        self.insert_field_names_local(ctor_def_id, &variant.data);
+        self.insert_field_names_local(ctor_def_id.to_def_id(), &variant.data);
 
         visit::walk_variant(self, variant);
     }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 5d5088d..cf9eae8 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -76,6 +76,7 @@
         let def_data = match &i.kind {
             ItemKind::Impl { .. } => DefPathData::Impl,
             ItemKind::Mod(..) if i.ident.name == kw::Invalid => {
+                // Fake crate root item from expand.
                 return visit::walk_item(self, i);
             }
             ItemKind::Mod(..)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 612bc3e..33ab09a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -469,24 +469,17 @@
             ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
                 let mut err = self.session.struct_span_err(
                     span,
-                    "generic parameters must not be used inside of non trivial constant values",
+                    "generic parameters may not be used in const operations",
                 );
-                err.span_label(
-                    span,
-                    &format!(
-                        "non-trivial anonymous constants must not depend on the parameter `{}`",
-                        name
-                    ),
-                );
+                err.span_label(span, &format!("cannot perform const operation using `{}`", name));
 
                 if is_type {
-                    err.note("type parameters are currently not permitted in anonymous constants");
+                    err.note("type parameters may not be used in const expressions");
                 } else {
-                    err.help(
-                        &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants",
-                                 name
-                        )
-                    );
+                    err.help(&format!(
+                        "const parameters may only be used as standalone arguments, i.e. `{}`",
+                        name
+                    ));
                 }
 
                 err
@@ -929,6 +922,17 @@
         );
         self.add_typo_suggestion(err, suggestion, ident.span);
 
+        let import_suggestions = self.lookup_import_candidates(
+            ident,
+            Namespace::MacroNS,
+            parent_scope,
+            |res| match res {
+                Res::Def(DefKind::Macro(MacroKind::Bang), _) => true,
+                _ => false,
+            },
+        );
+        show_candidates(err, None, &import_suggestions, false, true);
+
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
             let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
             err.span_note(ident.span, &msg);
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index b02fc42..adff454 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -875,12 +875,6 @@
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
         let orig_vis = import.vis.replace(ty::Visibility::Invisible);
-        let orig_unusable_binding = match &import.kind {
-            ImportKind::Single { target_bindings, .. } => {
-                Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get()))
-            }
-            _ => None,
-        };
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
         let path_res = self.r.resolve_path(
             &import.module_path,
@@ -891,9 +885,6 @@
             import.crate_lint(),
         );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
-        if let Some(orig_unusable_binding) = orig_unusable_binding {
-            self.r.unusable_binding = orig_unusable_binding;
-        }
         import.vis.set(orig_vis);
         if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
             // Consider erroneous imports used to avoid duplicate diagnostics.
@@ -904,7 +895,8 @@
                 // Consistency checks, analogous to `finalize_macro_resolutions`.
                 if let Some(initial_module) = import.imported_module.get() {
                     if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity {
-                        span_bug!(import.span, "inconsistent resolution for an import");
+                        let msg = "inconsistent resolution for an import";
+                        self.r.session.span_err(import.span, msg);
                     }
                 } else {
                     if self.r.privacy_errors.is_empty() {
@@ -926,7 +918,6 @@
             }
             PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => {
                 if no_ambiguity {
-                    assert!(import.imported_module.get().is_none());
                     let err = match self.make_path_suggestion(
                         span,
                         import.module_path.clone(),
@@ -1157,7 +1148,7 @@
                     }
                     _ => {
                         if !ident.is_path_segment_keyword() {
-                            format!("no `{}` external crate", ident)
+                            format!("no external crate `{}`", ident)
                         } else {
                             // HACK(eddyb) this shows up for `self` & `super`, which
                             // should work instead - for now keep the same error message.
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2c01934..7517ab6 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -369,7 +369,7 @@
     /// param.
     currently_processing_generics: bool,
 
-    /// The current enclosing function (used for better errors).
+    /// The current enclosing (non-closure) function (used for better errors).
     current_function: Option<(FnKind<'ast>, Span)>,
 
     /// A list of labels as of yet unused. Labels will be removed from this map when
@@ -384,6 +384,13 @@
 
     /// Used to detect possible `if let` written without `let` and to provide structured suggestion.
     in_if_condition: Option<&'ast Expr>,
+
+    /// If we are currently in a trait object definition. Used to point at the bounds when
+    /// encountering a struct or enum.
+    current_trait_object: Option<&'ast [ast::GenericBound]>,
+
+    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
+    current_where_predicate: Option<&'ast WherePredicate>,
 }
 
 struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -453,6 +460,7 @@
         self.diagnostic_metadata.current_let_binding = original;
     }
     fn visit_ty(&mut self, ty: &'ast Ty) {
+        let prev = self.diagnostic_metadata.current_trait_object;
         match ty.kind {
             TyKind::Path(ref qself, ref path) => {
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
@@ -464,9 +472,13 @@
                     .map_or(Res::Err, |d| d.res());
                 self.r.record_partial_res(ty.id, PartialRes::new(res));
             }
+            TyKind::TraitObject(ref bounds, ..) => {
+                self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
+            }
             _ => (),
         }
         visit::walk_ty(self, ty);
+        self.diagnostic_metadata.current_trait_object = prev;
     }
     fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
         self.smart_resolve_path(
@@ -503,8 +515,10 @@
             FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind,
             FnKind::Closure(..) => ClosureOrAsyncRibKind,
         };
-        let previous_value =
-            replace(&mut self.diagnostic_metadata.current_function, Some((fn_kind, sp)));
+        let previous_value = self.diagnostic_metadata.current_function;
+        if matches!(fn_kind, FnKind::Fn(..)) {
+            self.diagnostic_metadata.current_function = Some((fn_kind, sp));
+        }
         debug!("(resolving function) entering function");
         let declaration = fn_kind.decl();
 
@@ -660,6 +674,14 @@
         }
         self.diagnostic_metadata.currently_processing_generics = prev;
     }
+
+    fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
+        debug!("visit_where_predicate {:?}", p);
+        let previous_value =
+            replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p));
+        visit::walk_where_predicate(self, p);
+        self.diagnostic_metadata.current_where_predicate = previous_value;
+    }
 }
 
 impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index ced272e..c24b383 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,6 +1,6 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
 use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
-use crate::late::{LateResolutionVisitor, RibKind};
+use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
 use crate::path_names_to_string;
 use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
@@ -8,17 +8,19 @@
 use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::visit::FnKind;
 use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
+use rustc_ast_pretty::pprust::path_segment_to_string;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, CtorKind, DefKind};
+use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::config::nightly_options;
+use rustc_session::parse::feature_err;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 
 use tracing::debug;
 
@@ -438,27 +440,213 @@
             }
         }
 
-        if !self.type_ascription_suggestion(&mut err, base_span)
-            && !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span)
-        {
-            // Fallback label.
-            err.span_label(base_span, fallback_label);
+        if !self.type_ascription_suggestion(&mut err, base_span) {
+            let mut fallback = false;
+            if let (
+                PathSource::Trait(AliasPossibility::Maybe),
+                Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
+            ) = (source, res)
+            {
+                if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
+                    fallback = true;
+                    let spans: Vec<Span> = bounds
+                        .iter()
+                        .map(|bound| bound.span())
+                        .filter(|&sp| sp != base_span)
+                        .collect();
 
-            match self.diagnostic_metadata.current_let_binding {
-                Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => {
-                    err.span_suggestion_short(
-                        pat_sp.between(ty_sp),
-                        "use `=` if you meant to assign",
-                        " = ".to_string(),
-                        Applicability::MaybeIncorrect,
+                    let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap();
+                    // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
+                    let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap();
+                    // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
+                    let last_bound_span = spans.last().cloned().unwrap();
+                    let mut multi_span: MultiSpan = spans.clone().into();
+                    for sp in spans {
+                        let msg = if sp == last_bound_span {
+                            format!(
+                                "...because of {} bound{}",
+                                if bounds.len() <= 2 { "this" } else { "these" },
+                                if bounds.len() <= 2 { "" } else { "s" },
+                            )
+                        } else {
+                            String::new()
+                        };
+                        multi_span.push_span_label(sp, msg);
+                    }
+                    multi_span.push_span_label(
+                        base_span,
+                        "expected this type to be a trait...".to_string(),
                     );
+                    err.span_help(
+                        multi_span,
+                        "`+` is used to constrain a \"trait object\" type with lifetimes or \
+                         auto-traits; structs and enums can't be bound in that way",
+                    );
+                    if bounds.iter().all(|bound| match bound {
+                        ast::GenericBound::Outlives(_) => true,
+                        ast::GenericBound::Trait(tr, _) => tr.span == base_span,
+                    }) {
+                        let mut sugg = vec![];
+                        if base_span != start_span {
+                            sugg.push((start_span.until(base_span), String::new()));
+                        }
+                        if base_span != end_span {
+                            sugg.push((base_span.shrink_to_hi().to(end_span), String::new()));
+                        }
+
+                        err.multipart_suggestion(
+                            "if you meant to use a type and not a trait here, remove the bounds",
+                            sugg,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
-                _ => {}
+            }
+
+            fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
+
+            if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
+                fallback = true;
+                match self.diagnostic_metadata.current_let_binding {
+                    Some((pat_sp, Some(ty_sp), None))
+                        if ty_sp.contains(base_span) && could_be_expr =>
+                    {
+                        err.span_suggestion_short(
+                            pat_sp.between(ty_sp),
+                            "use `=` if you meant to assign",
+                            " = ".to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => {}
+                }
+            }
+            if fallback {
+                // Fallback label.
+                err.span_label(base_span, fallback_label);
             }
         }
         (err, candidates)
     }
 
+    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
+    fn restrict_assoc_type_in_where_clause(
+        &mut self,
+        span: Span,
+        err: &mut DiagnosticBuilder<'_>,
+    ) -> bool {
+        // Detect that we are actually in a `where` predicate.
+        let (bounded_ty, bounds, where_span) =
+            if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                bounded_ty,
+                bound_generic_params,
+                bounds,
+                span,
+            })) = self.diagnostic_metadata.current_where_predicate
+            {
+                if !bound_generic_params.is_empty() {
+                    return false;
+                }
+                (bounded_ty, bounds, span)
+            } else {
+                return false;
+            };
+
+        // Confirm that the target is an associated type.
+        let (ty, position, path) = if let ast::TyKind::Path(
+            Some(ast::QSelf { ty, position, .. }),
+            path,
+        ) = &bounded_ty.kind
+        {
+            // use this to verify that ident is a type param.
+            let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+                bounded_ty.id,
+                None,
+                &Segment::from_path(path),
+                Namespace::TypeNS,
+                span,
+                true,
+                CrateLint::No,
+            ) {
+                partial_res
+            } else {
+                return false;
+            };
+            if !(matches!(
+                partial_res.base_res(),
+                hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
+            ) && partial_res.unresolved_segments() == 0)
+            {
+                return false;
+            }
+            (ty, position, path)
+        } else {
+            return false;
+        };
+
+        if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind {
+            // Confirm that the `SelfTy` is a type parameter.
+            let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+                bounded_ty.id,
+                None,
+                &Segment::from_path(type_param_path),
+                Namespace::TypeNS,
+                span,
+                true,
+                CrateLint::No,
+            ) {
+                partial_res
+            } else {
+                return false;
+            };
+            if !(matches!(
+                partial_res.base_res(),
+                hir::def::Res::Def(hir::def::DefKind::TyParam, _)
+            ) && partial_res.unresolved_segments() == 0)
+            {
+                return false;
+            }
+            if let (
+                [ast::PathSegment { ident: constrain_ident, args: None, .. }],
+                [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)],
+            ) = (&type_param_path.segments[..], &bounds[..])
+            {
+                if let [ast::PathSegment { ident, args: None, .. }] =
+                    &poly_trait_ref.trait_ref.path.segments[..]
+                {
+                    if ident.span == span {
+                        err.span_suggestion_verbose(
+                            *where_span,
+                            &format!("constrain the associated type to `{}`", ident),
+                            format!(
+                                "{}: {}<{} = {}>",
+                                self.r
+                                    .session
+                                    .source_map()
+                                    .span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`.
+                                    .unwrap_or_else(|_| constrain_ident.to_string()),
+                                path.segments[..*position]
+                                    .iter()
+                                    .map(|segment| path_segment_to_string(segment))
+                                    .collect::<Vec<_>>()
+                                    .join("::"),
+                                path.segments[*position..]
+                                    .iter()
+                                    .map(|segment| path_segment_to_string(segment))
+                                    .collect::<Vec<_>>()
+                                    .join("::"),
+                                ident,
+                            ),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
     /// Check if the source is call expression and the first argument is `self`. If true,
     /// return the span of whole call and the span for all arguments expect the first one (`self`).
     fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
@@ -725,24 +913,8 @@
                     // We already suggested changing `:` into `::` during parsing.
                     return false;
                 }
-                if let Some(variants) = self.collect_enum_variants(def_id) {
-                    if !variants.is_empty() {
-                        let msg = if variants.len() == 1 {
-                            "try using the enum's variant"
-                        } else {
-                            "try using one of the enum's variants"
-                        };
 
-                        err.span_suggestions(
-                            span,
-                            msg,
-                            variants.iter().map(path_names_to_string),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                } else {
-                    err.note("you might have meant to use one of the enum's variants");
-                }
+                self.suggest_using_enum_variant(err, source, def_id, span);
             }
             (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
                 if let Some((ctor_def, ctor_vis, fields)) =
@@ -1125,20 +1297,165 @@
         result
     }
 
-    fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
+    fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
         self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
             let mut variants = Vec::new();
             enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
-                if let Res::Def(DefKind::Variant, _) = name_binding.res() {
+                if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
                     let mut segms = enum_import_suggestion.path.segments.clone();
                     segms.push(ast::PathSegment::from_ident(ident));
-                    variants.push(Path { span: name_binding.span, segments: segms, tokens: None });
+                    let path = Path { span: name_binding.span, segments: segms, tokens: None };
+                    variants.push((path, def_id, kind));
                 }
             });
             variants
         })
     }
 
+    /// Adds a suggestion for using an enum's variant when an enum is used instead.
+    fn suggest_using_enum_variant(
+        &mut self,
+        err: &mut DiagnosticBuilder<'a>,
+        source: PathSource<'_>,
+        def_id: DefId,
+        span: Span,
+    ) {
+        let variants = match self.collect_enum_ctors(def_id) {
+            Some(variants) => variants,
+            None => {
+                err.note("you might have meant to use one of the enum's variants");
+                return;
+            }
+        };
+
+        let suggest_only_tuple_variants =
+            matches!(source, PathSource::TupleStruct(..)) || source.is_call();
+        if suggest_only_tuple_variants {
+            // Suggest only tuple variants regardless of whether they have fields and do not
+            // suggest path with added parenthesis.
+            let mut suggestable_variants = variants
+                .iter()
+                .filter(|(.., kind)| *kind == CtorKind::Fn)
+                .map(|(variant, ..)| path_names_to_string(variant))
+                .collect::<Vec<_>>();
+
+            let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
+
+            let source_msg = if source.is_call() {
+                "to construct"
+            } else if matches!(source, PathSource::TupleStruct(..)) {
+                "to match against"
+            } else {
+                unreachable!()
+            };
+
+            if !suggestable_variants.is_empty() {
+                let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
+                    format!("try {} the enum's variant", source_msg)
+                } else {
+                    format!("try {} one of the enum's variants", source_msg)
+                };
+
+                err.span_suggestions(
+                    span,
+                    &msg,
+                    suggestable_variants.drain(..),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            // If the enum has no tuple variants..
+            if non_suggestable_variant_count == variants.len() {
+                err.help(&format!("the enum has no tuple variants {}", source_msg));
+            }
+
+            // If there are also non-tuple variants..
+            if non_suggestable_variant_count == 1 {
+                err.help(&format!(
+                    "you might have meant {} the enum's non-tuple variant",
+                    source_msg
+                ));
+            } else if non_suggestable_variant_count >= 1 {
+                err.help(&format!(
+                    "you might have meant {} one of the enum's non-tuple variants",
+                    source_msg
+                ));
+            }
+        } else {
+            let needs_placeholder = |def_id: DefId, kind: CtorKind| {
+                let has_no_fields =
+                    self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false);
+                match kind {
+                    CtorKind::Const => false,
+                    CtorKind::Fn | CtorKind::Fictive if has_no_fields => false,
+                    _ => true,
+                }
+            };
+
+            let mut suggestable_variants = variants
+                .iter()
+                .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
+                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
+                .map(|(variant, kind)| match kind {
+                    CtorKind::Const => variant,
+                    CtorKind::Fn => format!("({}())", variant),
+                    CtorKind::Fictive => format!("({} {{}})", variant),
+                })
+                .collect::<Vec<_>>();
+
+            if !suggestable_variants.is_empty() {
+                let msg = if suggestable_variants.len() == 1 {
+                    "you might have meant to use the following enum variant"
+                } else {
+                    "you might have meant to use one of the following enum variants"
+                };
+
+                err.span_suggestions(
+                    span,
+                    msg,
+                    suggestable_variants.drain(..),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            let mut suggestable_variants_with_placeholders = variants
+                .iter()
+                .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
+                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
+                .filter_map(|(variant, kind)| match kind {
+                    CtorKind::Fn => Some(format!("({}(/* fields */))", variant)),
+                    CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)),
+                    _ => None,
+                })
+                .collect::<Vec<_>>();
+
+            if !suggestable_variants_with_placeholders.is_empty() {
+                let msg = match (
+                    suggestable_variants.is_empty(),
+                    suggestable_variants_with_placeholders.len(),
+                ) {
+                    (true, 1) => "the following enum variant is available",
+                    (true, _) => "the following enum variants are available",
+                    (false, 1) => "alternatively, the following enum variant is available",
+                    (false, _) => "alternatively, the following enum variants are also available",
+                };
+
+                err.span_suggestions(
+                    span,
+                    msg,
+                    suggestable_variants_with_placeholders.drain(..),
+                    Applicability::HasPlaceholders,
+                );
+            }
+        };
+
+        if def_id.is_local() {
+            if let Some(span) = self.def_span(def_id) {
+                err.span_note(span, "the enum is defined here");
+            }
+        }
+    }
+
     crate fn report_missing_type_error(
         &self,
         path: &[Segment],
@@ -1599,4 +1916,32 @@
             _ => {}
         }
     }
+
+    /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics` so
+    /// this function will emit an error if `min_const_generics` is enabled, the body identified by
+    /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
+    crate fn maybe_emit_forbidden_non_static_lifetime_error(
+        &self,
+        body_id: hir::BodyId,
+        lifetime_ref: &'tcx hir::Lifetime,
+    ) {
+        let is_anon_const = matches!(
+            self.tcx.def_kind(self.tcx.hir().body_owner_def_id(body_id)),
+            hir::def::DefKind::AnonConst
+        );
+        let is_allowed_lifetime = matches!(
+            lifetime_ref.name,
+            hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
+        );
+
+        if self.tcx.features().min_const_generics && is_anon_const && !is_allowed_lifetime {
+            feature_err(
+                &self.tcx.sess.parse_sess,
+                sym::const_generics,
+                lifetime_ref.span,
+                "a non-static lifetime is not allowed in a `const`",
+            )
+            .emit();
+        }
+    }
 }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 31360d4..072fb50 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -1777,6 +1777,10 @@
         let result = loop {
             match *scope {
                 Scope::Body { id, s } => {
+                    // Non-static lifetimes are prohibited in anonymous constants under
+                    // `min_const_generics`.
+                    self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref);
+
                     outermost_body = Some(id);
                     scope = s;
                 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 283db14..b12e516 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -19,7 +19,7 @@
 
 use Determinacy::*;
 
-use rustc_arena::TypedArena;
+use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::unwrap_or;
 use rustc_ast::visit::{self, Visitor};
@@ -218,7 +218,7 @@
     ParamInTyOfConstParam(Symbol),
     /// constant values inside of type parameter defaults must not depend on generic parameters.
     ParamInAnonConstInTyDefault(Symbol),
-    /// generic parameters must not be used inside of non trivial constant values.
+    /// generic parameters must not be used inside const evaluations.
     ///
     /// This error is only emitted when using `min_const_generics`.
     ParamInNonTrivialAnonConst { name: Symbol, is_type: bool },
@@ -944,7 +944,8 @@
 
     /// Maps glob imports to the names of items actually imported.
     glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
-
+    /// Visibilities in "lowered" form, for all entities that have them.
+    visibilities: FxHashMap<LocalDefId, ty::Visibility>,
     used_imports: FxHashSet<(NodeId, Namespace)>,
     maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -1008,10 +1009,6 @@
     /// Features enabled for this crate.
     active_features: FxHashSet<Symbol>,
 
-    /// Stores enum visibilities to properly build a reduced graph
-    /// when visiting the correspondent variants.
-    variant_vis: DefIdMap<ty::Visibility>,
-
     lint_buffer: LintBuffer,
 
     next_node_id: NodeId,
@@ -1028,6 +1025,9 @@
     invocation_parents: FxHashMap<ExpnId, LocalDefId>,
 
     next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
+    /// Some way to know that we are in a *trait* impl in `visit_assoc_item`.
+    /// FIXME: Replace with a more general AST map (together with some other fields).
+    trait_impl_items: FxHashSet<LocalDefId>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1035,12 +1035,10 @@
 pub struct ResolverArenas<'a> {
     modules: TypedArena<ModuleData<'a>>,
     local_modules: RefCell<Vec<Module<'a>>>,
-    name_bindings: TypedArena<NameBinding<'a>>,
     imports: TypedArena<Import<'a>>,
     name_resolutions: TypedArena<RefCell<NameResolution<'a>>>,
-    macro_rules_bindings: TypedArena<MacroRulesBinding<'a>>,
     ast_paths: TypedArena<ast::Path>,
-    pattern_spans: TypedArena<Span>,
+    dropless: DroplessArena,
 }
 
 impl<'a> ResolverArenas<'a> {
@@ -1055,7 +1053,7 @@
         self.local_modules.borrow()
     }
     fn alloc_name_binding(&'a self, name_binding: NameBinding<'a>) -> &'a NameBinding<'a> {
-        self.name_bindings.alloc(name_binding)
+        self.dropless.alloc(name_binding)
     }
     fn alloc_import(&'a self, import: Import<'a>) -> &'a Import<'_> {
         self.imports.alloc(import)
@@ -1067,13 +1065,13 @@
         &'a self,
         binding: MacroRulesBinding<'a>,
     ) -> &'a MacroRulesBinding<'a> {
-        self.macro_rules_bindings.alloc(binding)
+        self.dropless.alloc(binding)
     }
     fn alloc_ast_paths(&'a self, paths: &[ast::Path]) -> &'a [ast::Path] {
         self.ast_paths.alloc_from_iter(paths.iter().cloned())
     }
     fn alloc_pattern_spans(&'a self, spans: impl Iterator<Item = Span>) -> &'a [Span] {
-        self.pattern_spans.alloc_from_iter(spans)
+        self.dropless.alloc_from_iter(spans)
     }
 }
 
@@ -1195,7 +1193,8 @@
         metadata_loader: &'a MetadataLoaderDyn,
         arenas: &'a ResolverArenas<'a>,
     ) -> Resolver<'a> {
-        let root_def_id = DefId::local(CRATE_DEF_INDEX);
+        let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX };
+        let root_def_id = root_local_def_id.to_def_id();
         let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
         let graph_root = arenas.alloc_module(ModuleData {
             no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude),
@@ -1213,11 +1212,14 @@
             )
         });
         let mut module_map = FxHashMap::default();
-        module_map.insert(LocalDefId { local_def_index: CRATE_DEF_INDEX }, graph_root);
+        module_map.insert(root_local_def_id, graph_root);
 
         let definitions = Definitions::new(crate_name, session.local_crate_disambiguator());
         let root = definitions.get_root_def();
 
+        let mut visibilities = FxHashMap::default();
+        visibilities.insert(root_local_def_id, ty::Visibility::Public);
+
         let mut def_id_to_span = IndexVec::default();
         assert_eq!(def_id_to_span.push(rustc_span::DUMMY_SP), root);
         let mut def_id_to_node_id = IndexVec::default();
@@ -1240,9 +1242,6 @@
             extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
             if !session.contains_name(&krate.attrs, sym::no_std) {
                 extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
-                if session.rust_2018() {
-                    extern_prelude.insert(Ident::with_dummy_span(sym::meta), Default::default());
-                }
             }
         }
 
@@ -1293,7 +1292,7 @@
             ast_transform_scopes: FxHashMap::default(),
 
             glob_map: Default::default(),
-
+            visibilities,
             used_imports: FxHashSet::default(),
             maybe_unused_trait_imports: Default::default(),
             maybe_unused_extern_crates: Vec::new(),
@@ -1342,7 +1341,6 @@
                 .map(|(feat, ..)| *feat)
                 .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
                 .collect(),
-            variant_vis: Default::default(),
             lint_buffer: LintBuffer::default(),
             next_node_id: NodeId::from_u32(1),
             def_id_to_span,
@@ -1351,6 +1349,7 @@
             placeholder_field_indices: Default::default(),
             invocation_parents,
             next_disambiguator: Default::default(),
+            trait_impl_items: Default::default(),
         }
     }
 
@@ -1374,6 +1373,7 @@
 
     pub fn into_outputs(self) -> ResolverOutputs {
         let definitions = self.definitions;
+        let visibilities = self.visibilities;
         let extern_crate_map = self.extern_crate_map;
         let export_map = self.export_map;
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
@@ -1382,6 +1382,7 @@
         ResolverOutputs {
             definitions: definitions,
             cstore: Box::new(self.crate_loader.into_cstore()),
+            visibilities,
             extern_crate_map,
             export_map,
             glob_map,
@@ -1399,6 +1400,7 @@
         ResolverOutputs {
             definitions: self.definitions.clone(),
             cstore: Box::new(self.cstore().clone()),
+            visibilities: self.visibilities.clone(),
             extern_crate_map: self.extern_crate_map.clone(),
             export_map: self.export_map.clone(),
             glob_map: self.glob_map.clone(),
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index fa4423e..8b79c93 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -107,7 +107,7 @@
 
     #[inline]
     fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        let as_u8: u8 = unsafe { ::std::mem::transmute(v) };
+        let as_u8: u8 = unsafe { std::mem::transmute(v) };
         self.emit_u8(as_u8)
     }
 
@@ -300,13 +300,13 @@
     #[inline]
     fn read_char(&mut self) -> Result<char, Self::Error> {
         let bits = self.read_u32()?;
-        Ok(::std::char::from_u32(bits).unwrap())
+        Ok(std::char::from_u32(bits).unwrap())
     }
 
     #[inline]
     fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> {
         let len = self.read_usize()?;
-        let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
+        let s = std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
         self.position += len;
         Ok(Cow::Borrowed(s))
     }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ab96b03..f33bebf 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -34,11 +34,6 @@
 use std::path::{Path, PathBuf};
 use std::str::{self, FromStr};
 
-pub struct Config {
-    pub target: Target,
-    pub ptr_width: u32,
-}
-
 bitflags! {
     #[derive(Default, Encodable, Decodable)]
     pub struct SanitizerSet: u8 {
@@ -740,16 +735,16 @@
 }
 
 pub fn default_configuration(sess: &Session) -> CrateConfig {
-    let end = &sess.target.target.target_endian;
-    let arch = &sess.target.target.arch;
-    let wordsz = &sess.target.target.target_pointer_width;
-    let os = &sess.target.target.target_os;
-    let env = &sess.target.target.target_env;
-    let vendor = &sess.target.target.target_vendor;
-    let min_atomic_width = sess.target.target.min_atomic_width();
-    let max_atomic_width = sess.target.target.max_atomic_width();
-    let atomic_cas = sess.target.target.options.atomic_cas;
-    let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| {
+    let end = &sess.target.target_endian;
+    let arch = &sess.target.arch;
+    let wordsz = sess.target.pointer_width.to_string();
+    let os = &sess.target.target_os;
+    let env = &sess.target.target_env;
+    let vendor = &sess.target.target_vendor;
+    let min_atomic_width = sess.target.min_atomic_width();
+    let max_atomic_width = sess.target.max_atomic_width();
+    let atomic_cas = sess.target.options.atomic_cas;
+    let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
         sess.fatal(&err);
     });
 
@@ -757,7 +752,7 @@
     ret.reserve(6); // the minimum number of insertions
     // Target bindings.
     ret.insert((sym::target_os, Some(Symbol::intern(os))));
-    if let Some(ref fam) = sess.target.target.options.target_family {
+    if let Some(ref fam) = sess.target.options.target_family {
         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
         if fam == "windows" {
             ret.insert((sym::windows, None));
@@ -767,10 +762,10 @@
     }
     ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
     ret.insert((sym::target_endian, Some(Symbol::intern(end))));
-    ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz))));
+    ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
     ret.insert((sym::target_env, Some(Symbol::intern(env))));
     ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
-    if sess.target.target.options.has_elf_tls {
+    if sess.target.options.has_elf_tls {
         ret.insert((sym::target_thread_local, None));
     }
     for &(i, align) in &[
@@ -792,7 +787,7 @@
             };
             let s = i.to_string();
             insert_atomic(&s, align);
-            if &s == wordsz {
+            if s == wordsz {
                 insert_atomic("ptr", layout.pointer_align.abi);
             }
         }
@@ -831,7 +826,7 @@
     user_cfg
 }
 
-pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Config {
+pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
     let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
     let target = target_result.unwrap_or_else(|e| {
         early_error(
@@ -844,21 +839,18 @@
         )
     });
 
-    let ptr_width = match &target.target_pointer_width[..] {
-        "16" => 16,
-        "32" => 32,
-        "64" => 64,
-        w => early_error(
+    if !matches!(target.pointer_width, 16 | 32 | 64) {
+        early_error(
             opts.error_format,
             &format!(
                 "target specification was invalid: \
              unrecognized target-pointer-width {}",
-                w
+                target.pointer_width
             ),
-        ),
-    };
+        )
+    }
 
-    Config { target, ptr_width }
+    target
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -1756,10 +1748,6 @@
         );
     }
 
-    if debugging_opts.experimental_coverage {
-        debugging_opts.instrument_coverage = true;
-    }
-
     if debugging_opts.instrument_coverage {
         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
             early_error(
diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs
index 0cc97fb..fef3164 100644
--- a/compiler/rustc_session/src/lint/builtin.rs
+++ b/compiler/rustc_session/src/lint/builtin.rs
@@ -518,7 +518,7 @@
     /// ### Example
     ///
     /// ```rust
-    /// #![macro_export]
+    /// #![ignore]
     /// ```
     ///
     /// {{produces}}
@@ -1882,6 +1882,16 @@
 }
 
 declare_lint! {
+    /// The `invalid_html_tags` lint detects invalid HTML tags. This is a
+    /// `rustdoc` only lint, see the documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags
+    pub INVALID_HTML_TAGS,
+    Allow,
+    "detects invalid HTML tags in doc comments"
+}
+
+declare_lint! {
     /// The `where_clauses_object_safety` lint detects for [object safety] of
     /// [where clauses].
     ///
@@ -2699,6 +2709,7 @@
         INVALID_CODEBLOCK_ATTRIBUTES,
         MISSING_CRATE_LEVEL_DOCS,
         MISSING_DOC_CODE_EXAMPLES,
+        INVALID_HTML_TAGS,
         PRIVATE_DOC_TESTS,
         WHERE_CLAUSES_OBJECT_SAFETY,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 8cc55f4..627adcc 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -895,11 +895,6 @@
         all statements)."),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
-    experimental_coverage: bool = (false, parse_bool, [TRACKED],
-        "enable and extend the `-Z instrument-coverage` function-level coverage \
-        feature, adding additional experimental (likely inaccurate) counters and \
-        code regions (used by `rustc` compiler developers to test new coverage \
-        counter placements) (default: no)"),
     fewer_names: bool = (false, parse_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
         (default: no)"),
@@ -1008,6 +1003,10 @@
         "a single extra argument to prepend the linker invocation (can be used several times)"),
     pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
         "extra arguments to prepend to the linker invocation (space separated)"),
+    precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED],
+        "use a more precise version of drop elaboration for matches on enums (default: yes). \
+        This results in better codegen, but has caused miscompilations on some tier 2 platforms. \
+        See #77382 and #74551."),
     print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
         "make rustc print the total optimization fuel used by a crate"),
     print_link_args: bool = (false, parse_bool, [UNTRACKED],
@@ -1079,6 +1078,8 @@
         "show extended diagnostic help (default: no)"),
     terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
         "set the current terminal width"),
+    tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
+        "select processor to schedule for (`rustc --print target-cpus` for details)"),
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
     // We default to 1 here since we want to behave like
@@ -1115,6 +1116,8 @@
         `hir,typed` (HIR with types for each node),
         `hir-tree` (dump the raw HIR),
         `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
+    unsound_mir_opts: bool = (false, parse_bool, [TRACKED],
+        "enable unsound and buggy MIR optimizations (default: no)"),
     unstable_options: bool = (false, parse_bool, [UNTRACKED],
         "adds unstable command line options to rustc interface (default: no)"),
     use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index bf9c96c..0766c55 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -151,18 +151,16 @@
         CrateType::Rlib => outputs.out_directory.join(&format!("lib{}.rlib", libname)),
         CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
             let (prefix, suffix) =
-                (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix);
+                (&sess.target.options.dll_prefix, &sess.target.options.dll_suffix);
             outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
         }
         CrateType::Staticlib => {
-            let (prefix, suffix) = (
-                &sess.target.target.options.staticlib_prefix,
-                &sess.target.target.options.staticlib_suffix,
-            );
+            let (prefix, suffix) =
+                (&sess.target.options.staticlib_prefix, &sess.target.options.staticlib_suffix);
             outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
         }
         CrateType::Executable => {
-            let suffix = &sess.target.target.options.exe_suffix;
+            let suffix = &sess.target.options.exe_suffix;
             let out_filename = outputs.path(OutputType::Exe);
             if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
         }
@@ -179,35 +177,29 @@
 /// interaction with Rust code through static library is the only
 /// option for now
 pub fn default_output_for_target(sess: &Session) -> CrateType {
-    if !sess.target.target.options.executables {
-        CrateType::Staticlib
-    } else {
-        CrateType::Executable
-    }
+    if !sess.target.options.executables { CrateType::Staticlib } else { CrateType::Executable }
 }
 
 /// Checks if target supports crate_type as output
 pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool {
     match crate_type {
         CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro => {
-            if !sess.target.target.options.dynamic_linking {
+            if !sess.target.options.dynamic_linking {
                 return true;
             }
-            if sess.crt_static(Some(crate_type))
-                && !sess.target.target.options.crt_static_allows_dylibs
-            {
+            if sess.crt_static(Some(crate_type)) && !sess.target.options.crt_static_allows_dylibs {
                 return true;
             }
         }
         _ => {}
     }
-    if sess.target.target.options.only_cdylib {
+    if sess.target.options.only_cdylib {
         match crate_type {
             CrateType::ProcMacro | CrateType::Dylib => return true,
             _ => {}
         }
     }
-    if !sess.target.target.options.executables {
+    if !sess.target.options.executables {
         if crate_type == CrateType::Executable {
             return true;
         }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index ff5e615..8312f89 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -102,7 +102,7 @@
 /// Represents the data associated with a compilation
 /// session for a single crate.
 pub struct Session {
-    pub target: config::Config,
+    pub target: Target,
     pub host: Target,
     pub opts: config::Options,
     pub host_tlib_path: SearchPath,
@@ -614,7 +614,7 @@
     /// Calculates the flavor of LTO to use for this compilation.
     pub fn lto(&self) -> config::Lto {
         // If our target has codegen requirements ignore the command line
-        if self.target.target.options.requires_lto {
+        if self.target.options.requires_lto {
             return config::Lto::Fat;
         }
 
@@ -682,7 +682,7 @@
     /// Returns the panic strategy for this compile session. If the user explicitly selected one
     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
     pub fn panic_strategy(&self) -> PanicStrategy {
-        self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
+        self.opts.cg.panic.unwrap_or(self.target.options.panic_strategy)
     }
     pub fn fewer_names(&self) -> bool {
         let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
@@ -706,9 +706,9 @@
 
     /// Check whether this compile session and crate type use static crt.
     pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
-        if !self.target.target.options.crt_static_respected {
+        if !self.target.options.crt_static_respected {
             // If the target does not opt in to crt-static support, use its default.
-            return self.target.target.options.crt_static_default;
+            return self.target.options.crt_static_default;
         }
 
         let requested_features = self.opts.cg.target_feature.split(',');
@@ -725,20 +725,20 @@
             // We can't check `#![crate_type = "proc-macro"]` here.
             false
         } else {
-            self.target.target.options.crt_static_default
+            self.target.options.crt_static_default
         }
     }
 
     pub fn relocation_model(&self) -> RelocModel {
-        self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model)
+        self.opts.cg.relocation_model.unwrap_or(self.target.options.relocation_model)
     }
 
     pub fn code_model(&self) -> Option<CodeModel> {
-        self.opts.cg.code_model.or(self.target.target.options.code_model)
+        self.opts.cg.code_model.or(self.target.options.code_model)
     }
 
     pub fn tls_model(&self) -> TlsModel {
-        self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model)
+        self.opts.debugging_opts.tls_model.unwrap_or(self.target.options.tls_model)
     }
 
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
@@ -749,7 +749,7 @@
         } else if let Some(x) = self.opts.cg.force_frame_pointers {
             x
         } else {
-            !self.target.target.options.eliminate_frame_pointer
+            !self.target.options.eliminate_frame_pointer
         }
     }
 
@@ -773,7 +773,7 @@
         // value, if it is provided, or disable them, if not.
         if self.panic_strategy() == PanicStrategy::Unwind {
             true
-        } else if self.target.target.options.requires_uwtable {
+        } else if self.target.options.requires_uwtable {
             true
         } else {
             self.opts.cg.force_unwind_tables.unwrap_or(false)
@@ -944,7 +944,7 @@
         if let Some(n) = self.opts.cli_forced_codegen_units {
             return n;
         }
-        if let Some(n) = self.target.target.options.default_codegen_units {
+        if let Some(n) = self.target.options.default_codegen_units {
             return n as usize;
         }
 
@@ -1029,11 +1029,11 @@
     pub fn needs_plt(&self) -> bool {
         // Check if the current target usually needs PLT to be enabled.
         // The user can use the command line flag to override it.
-        let needs_plt = self.target.target.options.needs_plt;
+        let needs_plt = self.target.options.needs_plt;
 
         let dbg_opts = &self.opts.debugging_opts;
 
-        let relro_level = dbg_opts.relro_level.unwrap_or(self.target.target.options.relro_level);
+        let relro_level = dbg_opts.relro_level.unwrap_or(self.target.options.relro_level);
 
         // Only enable this optimization by default if full relro is also enabled.
         // In this case, lazy binding was already unavailable, so nothing is lost.
@@ -1057,8 +1057,7 @@
         match self.opts.cg.link_dead_code {
             Some(explicitly_set) => explicitly_set,
             None => {
-                self.opts.debugging_opts.instrument_coverage
-                    && !self.target.target.options.is_like_msvc
+                self.opts.debugging_opts.instrument_coverage && !self.target.options.is_like_msvc
                 // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid
                 // binaries when LLVM InstrProf counters are enabled). As described by this issue,
                 // the "link dead code" option produces incorrect binaries when compiled and linked
@@ -1259,7 +1258,7 @@
 
     let loader = file_loader.unwrap_or(Box::new(RealFileLoader));
     let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| {
-        if target_cfg.target.options.is_like_msvc {
+        if target_cfg.options.is_like_msvc {
             SourceFileHashAlgorithm::Sha1
         } else {
             SourceFileHashAlgorithm::Md5
@@ -1369,8 +1368,8 @@
         if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
     };
 
-    let asm_arch = if target_cfg.target.options.allow_asm {
-        InlineAsmArch::from_str(&target_cfg.target.arch).ok()
+    let asm_arch = if target_cfg.options.allow_asm {
+        InlineAsmArch::from_str(&target_cfg.arch).ok()
     } else {
         None
     };
@@ -1438,7 +1437,7 @@
     // the `dllimport` attributes and `__imp_` symbols in that case.
     if sess.opts.cg.linker_plugin_lto.enabled()
         && sess.opts.cg.prefer_dynamic
-        && sess.target.target.options.is_like_windows
+        && sess.target.options.is_like_windows
     {
         sess.err(
             "Linker plugin based LTO is not supported together with \
@@ -1466,7 +1465,7 @@
             );
         }
 
-        if sess.target.target.options.requires_uwtable && !include_uwtables {
+        if sess.target.options.requires_uwtable && !include_uwtables {
             sess.err(
                 "target requires unwind tables, they cannot be disabled with \
                      `-C force-unwind-tables=no`.",
@@ -1481,7 +1480,7 @@
     // We should only display this error if we're actually going to run PGO.
     // If we're just supposed to print out some data, don't show the error (#61002).
     if sess.opts.cg.profile_generate.enabled()
-        && sess.target.target.options.is_like_msvc
+        && sess.target.options.is_like_msvc
         && sess.panic_strategy() == PanicStrategy::Unwind
         && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs)
     {
@@ -1586,5 +1585,3 @@
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
     handler.struct_warn(msg).emit();
 }
-
-pub type CompileResult = Result<(), ErrorReported>;
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index aae7782..b24ede9 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -159,6 +159,7 @@
         DefId { krate: LOCAL_CRATE, index }
     }
 
+    /// Returns whether the item is defined in the crate currently being compiled.
     #[inline]
     pub fn is_local(self) -> bool {
         self.krate == LOCAL_CRATE
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index fb80dcb..31f3d8e 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -619,14 +619,6 @@
         HygieneData::with(|data| data.outer_mark(self))
     }
 
-    #[inline]
-    pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) {
-        HygieneData::with(|data| {
-            let (expn_id, transparency) = data.outer_mark(self);
-            (expn_id, transparency, data.expn_data(expn_id).clone())
-        })
-    }
-
     pub fn dollar_crate_name(self) -> Symbol {
         HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
     }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 96a6956..d036c07 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -60,6 +60,8 @@
 use sha1::Digest;
 use sha1::Sha1;
 
+use tracing::debug;
+
 #[cfg(test)]
 mod tests;
 
@@ -221,12 +223,6 @@
         }
     }
 
-    pub fn quote_expansion_source_code(src: &str) -> FileName {
-        let mut hasher = StableHasher::new();
-        src.hash(&mut hasher);
-        FileName::QuoteExpansion(hasher.finish())
-    }
-
     pub fn macro_expansion_source_code(src: &str) -> FileName {
         let mut hasher = StableHasher::new();
         src.hash(&mut hasher);
@@ -1462,6 +1458,88 @@
 
         BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
     }
+
+    /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
+    pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
+        // The number of extra bytes due to multibyte chars in the `SourceFile`.
+        let mut total_extra_bytes = 0;
+
+        for mbc in self.multibyte_chars.iter() {
+            debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
+            if mbc.pos < bpos {
+                // Every character is at least one byte, so we only
+                // count the actual extra bytes.
+                total_extra_bytes += mbc.bytes as u32 - 1;
+                // We should never see a byte position in the middle of a
+                // character.
+                assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
+            } else {
+                break;
+            }
+        }
+
+        assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32());
+        CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize)
+    }
+
+    /// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
+    /// given `BytePos`.
+    pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) {
+        let chpos = self.bytepos_to_file_charpos(pos);
+        match self.lookup_line(pos) {
+            Some(a) => {
+                let line = a + 1; // Line numbers start at 1
+                let linebpos = self.lines[a];
+                let linechpos = self.bytepos_to_file_charpos(linebpos);
+                let col = chpos - linechpos;
+                debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
+                debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
+                debug!("byte is on line: {}", line);
+                assert!(chpos >= linechpos);
+                (line, col)
+            }
+            None => (0, chpos),
+        }
+    }
+
+    /// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
+    /// column offset when displayed, for a given `BytePos`.
+    pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
+        let (line, col_or_chpos) = self.lookup_file_pos(pos);
+        if line > 0 {
+            let col = col_or_chpos;
+            let linebpos = self.lines[line - 1];
+            let col_display = {
+                let start_width_idx = self
+                    .non_narrow_chars
+                    .binary_search_by_key(&linebpos, |x| x.pos())
+                    .unwrap_or_else(|x| x);
+                let end_width_idx = self
+                    .non_narrow_chars
+                    .binary_search_by_key(&pos, |x| x.pos())
+                    .unwrap_or_else(|x| x);
+                let special_chars = end_width_idx - start_width_idx;
+                let non_narrow: usize = self.non_narrow_chars[start_width_idx..end_width_idx]
+                    .iter()
+                    .map(|x| x.width())
+                    .sum();
+                col.0 - special_chars + non_narrow
+            };
+            (line, col, col_display)
+        } else {
+            let chpos = col_or_chpos;
+            let col_display = {
+                let end_width_idx = self
+                    .non_narrow_chars
+                    .binary_search_by_key(&pos, |x| x.pos())
+                    .unwrap_or_else(|x| x);
+                let non_narrow: usize =
+                    self.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum();
+                chpos.0 - end_width_idx + non_narrow
+            };
+            (0, chpos, col_display)
+        }
+    }
 }
 
 /// Normalizes the source code and records the normalizations.
@@ -1777,7 +1855,7 @@
         }
 
         if *self == DUMMY_SP {
-            std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+            Hash::hash(&TAG_INVALID_SPAN, hasher);
             return;
         }
 
@@ -1788,28 +1866,28 @@
         let (file_lo, line_lo, col_lo) = match ctx.byte_pos_to_line_and_col(span.lo) {
             Some(pos) => pos,
             None => {
-                std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+                Hash::hash(&TAG_INVALID_SPAN, hasher);
                 span.ctxt.hash_stable(ctx, hasher);
                 return;
             }
         };
 
         if !file_lo.contains(span.hi) {
-            std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+            Hash::hash(&TAG_INVALID_SPAN, hasher);
             span.ctxt.hash_stable(ctx, hasher);
             return;
         }
 
-        std::hash::Hash::hash(&TAG_VALID_SPAN, hasher);
+        Hash::hash(&TAG_VALID_SPAN, hasher);
         // We truncate the stable ID hash and line and column numbers. The chances
         // of causing a collision this way should be minimal.
-        std::hash::Hash::hash(&(file_lo.name_hash as u64), hasher);
+        Hash::hash(&(file_lo.name_hash as u64), hasher);
 
         let col = (col_lo.0 as u64) & 0xFF;
         let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
         let len = ((span.hi - span.lo).0 as u64) << 32;
         let line_col_len = col | line | len;
-        std::hash::Hash::hash(&line_col_len, hasher);
+        Hash::hash(&line_col_len, hasher);
         span.ctxt.hash_stable(ctx, hasher);
     }
 }
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 37596b8..3b929c4 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -428,58 +428,22 @@
         }
     }
 
+    /// Return the SourceFile that contains the given `BytePos`
+    pub fn lookup_source_file(&self, pos: BytePos) -> Lrc<SourceFile> {
+        let idx = self.lookup_source_file_idx(pos);
+        (*self.files.borrow().source_files)[idx].clone()
+    }
+
     /// Looks up source information about a `BytePos`.
     pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
-        let chpos = self.bytepos_to_file_charpos(pos);
-        match self.lookup_line(pos) {
-            Ok(SourceFileAndLine { sf: f, line: a }) => {
-                let line = a + 1; // Line numbers start at 1
-                let linebpos = f.lines[a];
-                let linechpos = self.bytepos_to_file_charpos(linebpos);
-                let col = chpos - linechpos;
-
-                let col_display = {
-                    let start_width_idx = f
-                        .non_narrow_chars
-                        .binary_search_by_key(&linebpos, |x| x.pos())
-                        .unwrap_or_else(|x| x);
-                    let end_width_idx = f
-                        .non_narrow_chars
-                        .binary_search_by_key(&pos, |x| x.pos())
-                        .unwrap_or_else(|x| x);
-                    let special_chars = end_width_idx - start_width_idx;
-                    let non_narrow: usize = f.non_narrow_chars[start_width_idx..end_width_idx]
-                        .iter()
-                        .map(|x| x.width())
-                        .sum();
-                    col.0 - special_chars + non_narrow
-                };
-                debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
-                debug!("char pos {:?} is on the line at char pos {:?}", chpos, linechpos);
-                debug!("byte is on line: {}", line);
-                assert!(chpos >= linechpos);
-                Loc { file: f, line, col, col_display }
-            }
-            Err(f) => {
-                let col_display = {
-                    let end_width_idx = f
-                        .non_narrow_chars
-                        .binary_search_by_key(&pos, |x| x.pos())
-                        .unwrap_or_else(|x| x);
-                    let non_narrow: usize =
-                        f.non_narrow_chars[0..end_width_idx].iter().map(|x| x.width()).sum();
-                    chpos.0 - end_width_idx + non_narrow
-                };
-                Loc { file: f, line: 0, col: chpos, col_display }
-            }
-        }
+        let sf = self.lookup_source_file(pos);
+        let (line, col, col_display) = sf.lookup_file_pos_with_col_display(pos);
+        Loc { file: sf, line, col, col_display }
     }
 
     // If the corresponding `SourceFile` is empty, does not return a line number.
     pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceFile>> {
-        let idx = self.lookup_source_file_idx(pos);
-
-        let f = (*self.files.borrow().source_files)[idx].clone();
+        let f = self.lookup_source_file(pos);
 
         match f.lookup_line(pos) {
             Some(line) => Ok(SourceFileAndLine { sf: f, line }),
@@ -487,15 +451,6 @@
         }
     }
 
-    /// Returns a new `Span` covering the start and end `BytePos`s of the file containing the given
-    /// `pos`. This can be used to quickly determine if another `BytePos` or `Span` is from the same
-    /// file.
-    pub fn lookup_file_span(&self, pos: BytePos) -> Span {
-        let idx = self.lookup_source_file_idx(pos);
-        let SourceFile { start_pos, end_pos, .. } = *(*self.files.borrow().source_files)[idx];
-        Span::with_root_ctxt(start_pos, end_pos)
-    }
-
     /// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If
     /// there are gaps between LHS and RHS, the resulting union will cross these gaps.
     /// For this to work,
@@ -934,27 +889,8 @@
     /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
     pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
         let idx = self.lookup_source_file_idx(bpos);
-        let map = &(*self.files.borrow().source_files)[idx];
-
-        // The number of extra bytes due to multibyte chars in the `SourceFile`.
-        let mut total_extra_bytes = 0;
-
-        for mbc in map.multibyte_chars.iter() {
-            debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
-            if mbc.pos < bpos {
-                // Every character is at least one byte, so we only
-                // count the actual extra bytes.
-                total_extra_bytes += mbc.bytes as u32 - 1;
-                // We should never see a byte position in the middle of a
-                // character.
-                assert!(bpos.to_u32() >= mbc.pos.to_u32() + mbc.bytes as u32);
-            } else {
-                break;
-            }
-        }
-
-        assert!(map.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32());
-        CharPos(bpos.to_usize() - map.start_pos.to_usize() - total_extra_bytes as usize)
+        let sf = &(*self.files.borrow().source_files)[idx];
+        sf.bytepos_to_file_charpos(bpos)
     }
 
     // Returns the index of the `SourceFile` (in `self.files`) that contains `pos`.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 12134a8..9cf530d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -212,6 +212,7 @@
         _d,
         _e,
         _task_context,
+        a32,
         aarch64_target_feature,
         abi,
         abi_amdgpu_kernel,
@@ -256,6 +257,7 @@
         arbitrary_enum_discriminant,
         arbitrary_self_types,
         arith_offset,
+        arm,
         arm_target_feature,
         array,
         arrays,
@@ -337,6 +339,7 @@
         closure_to_fn_coercion,
         cmp,
         cmpxchg16b_target_feature,
+        cmse_nonsecure_entry,
         coerce_unsized,
         cold,
         column,
@@ -353,10 +356,12 @@
         const_extern_fn,
         const_fn,
         const_fn_floating_point_arithmetic,
+        const_fn_fn_ptr_basics,
         const_fn_transmute,
         const_fn_union,
         const_generics,
         const_if_match,
+        const_impl_trait,
         const_in_array_repeat_expressions,
         const_indexing,
         const_let,
@@ -413,6 +418,7 @@
         decl_macro,
         declare_lint_pass,
         decode,
+        default_alloc_error_handler,
         default_lib_allocator,
         default_type_parameter_fallback,
         default_type_params,
@@ -587,12 +593,15 @@
         infer_static_outlives_requirements,
         inlateout,
         inline,
+        inline_const,
         inout,
+        instruction_set,
         intel,
         into_iter,
         into_result,
         intrinsics,
         irrefutable_let_patterns,
+        isa_attribute,
         isize,
         issue,
         issue_5723_bootstrap,
@@ -884,7 +893,6 @@
         rustc,
         rustc_allocator,
         rustc_allocator_nounwind,
-        rustc_allow_const_fn_ptr,
         rustc_args_required_const,
         rustc_attrs,
         rustc_builtin_macro,
@@ -1062,6 +1070,7 @@
         sym,
         sync,
         sync_trait,
+        t32,
         target_arch,
         target_endian,
         target_env,
@@ -1106,6 +1115,7 @@
         try_trait,
         tt,
         tuple,
+        tuple_from_req,
         tuple_indexing,
         two_phase,
         ty,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index c0dacd2..3df5f16 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -10,7 +10,7 @@
 [dependencies]
 tracing = "0.1"
 punycode = "0.4.0"
-rustc-demangle = "0.1.16"
+rustc-demangle = "0.1.18"
 
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index b96e318..2c9caf7 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -115,7 +115,6 @@
         }
 
         // also include any type parameters (for generic items)
-        assert!(!substs.has_erasable_regions());
         substs.hash_stable(&mut hcx, &mut hasher);
 
         if let Some(instantiating_crate) = instantiating_crate {
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 75150a5..28b4a78 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -201,7 +201,7 @@
     //
     // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
     if is_foreign {
-        if tcx.sess.target.target.arch != "wasm32"
+        if tcx.sess.target.arch != "wasm32"
             || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)
         {
             if let Some(name) = attrs.link_name {
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 24850a8..822a835 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -5,7 +5,8 @@
 //! paths etc in all kinds of annoying scenarios.
 
 use rustc_hir as hir;
-use rustc_middle::ty::{Instance, TyCtxt};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 
 const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
@@ -35,8 +36,11 @@
         let def_id = tcx.hir().local_def_id(hir_id);
         for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
             if tcx.sess.check_name(attr, SYMBOL_NAME) {
-                // for now, can only use on monomorphic names
-                let instance = Instance::mono(tcx, def_id.to_def_id());
+                let def_id = def_id.to_def_id();
+                let instance = Instance::new(
+                    def_id,
+                    tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)),
+                );
                 let mangled = tcx.symbol_name(instance);
                 tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
                 if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
@@ -44,7 +48,7 @@
                     tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
                 }
             } else if tcx.sess.check_name(attr, DEF_PATH) {
-                let path = tcx.def_path_str(def_id.to_def_id());
+                let path = with_no_trimmed_paths(|| tcx.def_path_str(def_id.to_def_id()));
                 tcx.sess.span_err(attr.span, &format!("def-path({})", path));
             }
 
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 091d488..7833385 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -4,6 +4,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_middle::mir::interpret::sign_extend;
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
@@ -132,7 +133,7 @@
             self.push("u");
 
             // FIXME(eddyb) we should probably roll our own punycode implementation.
-            let mut punycode_bytes = match ::punycode::encode(ident) {
+            let mut punycode_bytes = match punycode::encode(ident) {
                 Ok(s) => s.into_bytes(),
                 Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident),
             };
@@ -259,7 +260,7 @@
     }
 
     fn print_impl_path(
-        self,
+        mut self,
         impl_def_id: DefId,
         substs: &'tcx [GenericArg<'tcx>],
         mut self_ty: Ty<'tcx>,
@@ -284,12 +285,37 @@
             }
         }
 
-        self.path_append_impl(
-            |cx| cx.print_def_path(parent_def_id, &[]),
-            &key.disambiguated_data,
-            self_ty,
-            impl_trait_ref,
-        )
+        self.push(match impl_trait_ref {
+            Some(_) => "X",
+            None => "M",
+        });
+
+        // Encode impl generic params if the substitutions contain parameters (implying
+        // polymorphization is enabled) and this isn't an inherent impl.
+        if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
+            self = self.path_generic_args(
+                |this| {
+                    this.path_append_ns(
+                        |cx| cx.print_def_path(parent_def_id, &[]),
+                        'I',
+                        key.disambiguated_data.disambiguator as u64,
+                        "",
+                    )
+                },
+                substs,
+            )?;
+        } else {
+            self.push_disambiguator(key.disambiguated_data.disambiguator as u64);
+            self = self.print_def_path(parent_def_id, &[])?;
+        }
+
+        self = self_ty.print(self)?;
+
+        if let Some(trait_ref) = impl_trait_ref {
+            self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
+        }
+
+        Ok(self)
     }
 
     fn print_region(mut self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
@@ -502,16 +528,31 @@
         }
         let start = self.out.len();
 
-        match ct.ty.kind() {
-            ty::Uint(_) => {}
+        let mut neg = false;
+        let val = match ct.ty.kind() {
+            ty::Uint(_) | ty::Bool | ty::Char => {
+                ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty)
+            }
+            ty::Int(_) => {
+                let param_env = ty::ParamEnv::reveal_all();
+                ct.try_eval_bits(self.tcx, param_env, ct.ty).and_then(|b| {
+                    let sz = self.tcx.layout_of(param_env.and(ct.ty)).ok()?.size;
+                    let val = sign_extend(b, sz) as i128;
+                    if val < 0 {
+                        neg = true;
+                    }
+                    Some(val.wrapping_abs() as u128)
+                })
+            }
             _ => {
                 bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
             }
-        }
-        self = ct.ty.print(self)?;
+        };
 
-        if let Some(bits) = ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty) {
-            let _ = write!(self.out, "{:x}_", bits);
+        if let Some(bits) = val {
+            // We only print the type if the const can be evaluated.
+            self = ct.ty.print(self)?;
+            let _ = write!(self.out, "{}{:x}_", if neg { "n" } else { "" }, bits);
         } else {
             // NOTE(eddyb) despite having the path, we need to
             // encode a placeholder, as the path could refer
@@ -537,6 +578,7 @@
         self.push_ident(&name);
         Ok(self)
     }
+
     fn path_qualified(
         mut self,
         self_ty: Ty<'tcx>,
@@ -551,24 +593,16 @@
     }
 
     fn path_append_impl(
-        mut self,
-        print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
-        disambiguated_data: &DisambiguatedDefPathData,
-        self_ty: Ty<'tcx>,
-        trait_ref: Option<ty::TraitRef<'tcx>>,
+        self,
+        _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+        _: &DisambiguatedDefPathData,
+        _: Ty<'tcx>,
+        _: Option<ty::TraitRef<'tcx>>,
     ) -> Result<Self::Path, Self::Error> {
-        self.push(match trait_ref {
-            Some(_) => "X",
-            None => "M",
-        });
-        self.push_disambiguator(disambiguated_data.disambiguator as u64);
-        self = print_prefix(self)?;
-        self = self_ty.print(self)?;
-        if let Some(trait_ref) = trait_ref {
-            self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
-        }
-        Ok(self)
+        // Inlined into `print_impl_path`
+        unreachable!()
     }
+
     fn path_append(
         self,
         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
@@ -602,6 +636,7 @@
             name.as_ref().map_or("", |s| &s[..]),
         )
     }
+
     fn path_generic_args(
         mut self,
         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 602c424..8f7e2bb 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -610,15 +610,3 @@
         Ok(())
     }
 }
-
-/// Returns the maximum size of return values to be passed by value in the Rust ABI.
-///
-/// Return values beyond this size will use an implicit out-pointer instead.
-pub fn max_ret_by_val<C: HasTargetSpec + HasDataLayout>(spec: &C) -> Size {
-    match spec.target_spec().arch.as_str() {
-        // System-V will pass return values up to 128 bits in RAX/RDX.
-        "x86_64" => Size::from_bits(128),
-
-        _ => spec.data_layout().pointer_size,
-    }
-}
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 3c1a2ea..047b8cf 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -164,12 +164,12 @@
             ));
         }
 
-        if dl.pointer_size.bits().to_string() != target.target_pointer_width {
+        if dl.pointer_size.bits() != target.pointer_width.into() {
             return Err(format!(
                 "inconsistent target specification: \"data-layout\" claims \
                                 pointers are {}-bit, while \"target-pointer-width\" is `{}`",
                 dl.pointer_size.bits(),
-                target.target_pointer_width
+                target.pointer_width
             ));
         }
 
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
index 638c52d..b19489a 100644
--- a/compiler/rustc_target/src/asm/mips.rs
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -32,11 +32,12 @@
 
     pub fn supported_types(
         self,
-        _arch: InlineAsmArch,
+        arch: InlineAsmArch,
     ) -> &'static [(InlineAsmType, Option<&'static str>)] {
-        match self {
-            Self::reg => types! { _: I8, I16, I32, F32; },
-            Self::freg => types! { _: F32; },
+        match (self, arch) {
+            (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; },
+            (Self::reg, _) => types! { _: I8, I16, I32, F32; },
+            (Self::freg, _) => types! { _: F32, F64; },
         }
     }
 }
@@ -44,31 +45,31 @@
 // The reserved registers are somewhat taken from <https://git.io/JUR1k#L150>.
 def_regs! {
     Mips MipsInlineAsmReg MipsInlineAsmRegClass {
-        v0: reg = ["$2", "$v0"],
-        v1: reg = ["$3", "$v1"],
-        a0: reg = ["$4", "$a0"],
-        a1: reg = ["$5", "$a1"],
-        a2: reg = ["$6", "$a2"],
-        a3: reg = ["$7", "$a3"],
+        r2: reg = ["$2"],
+        r3: reg = ["$3"],
+        r4: reg = ["$4"],
+        r5: reg = ["$5"],
+        r6: reg = ["$6"],
+        r7: reg = ["$7"],
         // FIXME: Reserve $t0, $t1 if in mips16 mode.
-        t0: reg = ["$8", "$t0"],
-        t1: reg = ["$9", "$t1"],
-        t2: reg = ["$10", "$t2"],
-        t3: reg = ["$11", "$t3"],
-        t4: reg = ["$12", "$t4"],
-        t5: reg = ["$13", "$t5"],
-        t6: reg = ["$14", "$t6"],
-        t7: reg = ["$15", "$t7"],
-        s0: reg = ["$16", "$s0"],
-        s1: reg = ["$17", "$s1"],
-        s2: reg = ["$18", "$s2"],
-        s3: reg = ["$19", "$s3"],
-        s4: reg = ["$20", "$s4"],
-        s5: reg = ["$21", "$s5"],
-        s6: reg = ["$22", "$s6"],
-        s7: reg = ["$23", "$s7"],
-        t8: reg = ["$24", "$t8"],
-        t9: reg = ["$25", "$t9"],
+        r8: reg = ["$8"],
+        r9: reg = ["$9"],
+        r10: reg = ["$10"],
+        r11: reg = ["$11"],
+        r12: reg = ["$12"],
+        r13: reg = ["$13"],
+        r14: reg = ["$14"],
+        r15: reg = ["$15"],
+        r16: reg = ["$16"],
+        r17: reg = ["$17"],
+        r18: reg = ["$18"],
+        r19: reg = ["$19"],
+        r20: reg = ["$20"],
+        r21: reg = ["$21"],
+        r22: reg = ["$22"],
+        r23: reg = ["$23"],
+        r24: reg = ["$24"],
+        r25: reg = ["$25"],
         f0: freg = ["$f0"],
         f1: freg = ["$f1"],
         f2: freg = ["$f2"],
@@ -101,21 +102,21 @@
         f29: freg = ["$f29"],
         f30: freg = ["$f30"],
         f31: freg = ["$f31"],
-        #error = ["$0", "$zero"] =>
+        #error = ["$0"] =>
             "constant zero cannot be used as an operand for inline asm",
-        #error = ["$1", "$at"] =>
+        #error = ["$1"] =>
             "reserved for assembler (Assembler Temp)",
-        #error = ["$26", "$k0"] =>
+        #error = ["$26"] =>
             "OS-reserved register cannot be used as an operand for inline asm",
-        #error = ["$27", "$k1"] =>
+        #error = ["$27"] =>
             "OS-reserved register cannot be used as an operand for inline asm",
-        #error = ["$28", "$gp"] =>
+        #error = ["$28"] =>
             "the global pointer cannot be used as an operand for inline asm",
-        #error = ["$29", "$sp"] =>
+        #error = ["$29"] =>
             "the stack pointer cannot be used as an operand for inline asm",
-        #error = ["$30", "$s8", "$fp"] =>
+        #error = ["$30"] =>
             "the frame pointer cannot be used as an operand for inline asm",
-        #error = ["$31", "$ra"] =>
+        #error = ["$31"] =>
             "the return address register cannot be used as an operand for inline asm",
     }
 }
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index e2f8e91..0d691dc 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -176,6 +176,7 @@
     Nvptx64,
     Hexagon,
     Mips,
+    Mips64,
 }
 
 impl FromStr for InlineAsmArch {
@@ -192,6 +193,7 @@
             "nvptx64" => Ok(Self::Nvptx64),
             "hexagon" => Ok(Self::Hexagon),
             "mips" => Ok(Self::Mips),
+            "mips64" => Ok(Self::Mips64),
             _ => Err(()),
         }
     }
@@ -259,7 +261,7 @@
             InlineAsmArch::Hexagon => {
                 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
-            InlineAsmArch::Mips => {
+            InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
                 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
         })
@@ -409,7 +411,9 @@
                 InlineAsmArch::Hexagon => {
                     Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
                 }
-                InlineAsmArch::Mips => Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?),
+                InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
+                    Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
+                }
             })
         })
     }
@@ -565,7 +569,7 @@
             hexagon::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
-        InlineAsmArch::Mips => {
+        InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
             let mut map = mips::regclass_map();
             mips::fill_reg_map(arch, has_feature, target, &mut map);
             map
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index 60daf10..c15bd9a 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "apple-a12".to_string();
     base.max_atomic_width = Some(128);
@@ -14,10 +14,10 @@
     let arch = "aarch64";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
-    Ok(Target {
+    Target {
         llvm_target,
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: arch.to_string(),
@@ -26,5 +26,5 @@
         target_vendor: "apple".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index 21dcec8..0019fc4 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::Arm64, AppleOS::iOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::Arm64);
+    Target {
         llvm_target: "arm64-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -33,5 +33,5 @@
                 .to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
index 2b0cd6c..276682c 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::Arm64, AppleOS::tvOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::Arm64);
+    Target {
         llvm_target: "arm64-apple-tvos".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -22,5 +22,5 @@
             forces_embed_bitcode: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
index aabfe45..1f81a03 100644
--- a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-fuchsia".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -16,5 +16,5 @@
         target_vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index e4ecc7a..1ed4f0d 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -1,18 +1,18 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.max_atomic_width = Some(128);
     // As documented in http://developer.android.com/ndk/guides/cpu-features.html
     // the neon (ASIMD) and FP must exist on all android aarch64 targets.
     base.features = "+neon,+fp-armv8".to_string();
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -21,5 +21,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
index 8c03f1e..32fa2d6 100644
--- a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
     base.features = "+neon,+fp-armv8".to_string();
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "pc".to_string(),
         linker_flavor: LinkerFlavor::Msvc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
index 1278b89..f9d6251 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.max_atomic_width = Some(128);
     base.unsupported_abis = super::arm_base::unsupported_abis();
     base.linker = Some("aarch64-unknown-cloudabi-cc".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-cloudabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
index 5ae592c..3d00829 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-freebsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -16,5 +16,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
index e07b8f7..a7050cb 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-hermit".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -16,5 +16,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
index 0361622..1025501 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_env: "gnu".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
@@ -20,5 +20,5 @@
             target_mcount: "\u{1}_mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
index dc613f3..f530163 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_env: "musl".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
@@ -20,5 +20,5 @@
             target_mcount: "\u{1}_mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
index 8c2f6fc..dcb157d 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.max_atomic_width = Some(128);
     base.unsupported_abis = super::arm_base::unsupported_abis();
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-netbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
index e012dce..6d3e729 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -8,7 +8,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,+neon,+fp-armv8".to_string(),
@@ -21,10 +21,10 @@
         unsupported_abis: super::arm_base::unsupported_abis(),
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-none".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -33,5 +33,5 @@
         arch: "aarch64".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
index e2aa6e3..784cd7e 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -8,7 +8,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,-neon,-fp-armv8".to_string(),
@@ -21,10 +21,10 @@
         unsupported_abis: super::arm_base::unsupported_abis(),
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-none".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -33,5 +33,5 @@
         arch: "aarch64".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
index fd726c7..e03690e 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.max_atomic_width = Some(128);
     base.unsupported_abis = super::arm_base::unsupported_abis();
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-openbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
index f347a2d..13adec9 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::redox_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-redox".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -16,5 +16,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
index 6a8d148..d6af5dd 100644
--- a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "uwp".to_string(),
         linker_flavor: LinkerFlavor::Msvc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
index 05f5d7d..6fce200 100644
--- a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
@@ -16,5 +16,5 @@
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index 0ea99af..0824bc3 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -9,8 +9,10 @@
         .unwrap()
         .push("-Wl,--allow-multiple-definition".to_string());
     base.is_like_android = true;
+    base.dwarf_version = Some(2);
     base.position_independent_executables = true;
     base.has_elf_tls = false;
     base.requires_uwtable = true;
+    base.crt_static_respected = false;
     base
 }
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index e7b565a..2e3c835 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -23,6 +23,7 @@
         executables: true,
         target_family: Some("unix".to_string()),
         is_like_osx: true,
+        dwarf_version: Some(2),
         has_rpath: true,
         dll_prefix: "lib".to_string(),
         dll_suffix: ".dylib".to_string(),
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index 0d0a0da..e34277d 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -1,8 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
-use std::env;
-use std::io;
-use std::path::Path;
-use std::process::Command;
+use crate::spec::TargetOptions;
 
 use Arch::*;
 #[allow(non_camel_case_types)]
@@ -16,108 +12,6 @@
     X86_64_macabi,
 }
 
-#[allow(non_camel_case_types)]
-#[derive(Copy, Clone)]
-pub enum AppleOS {
-    tvOS,
-    iOS,
-}
-
-impl Arch {
-    pub fn to_string(self) -> &'static str {
-        match self {
-            Armv7 => "armv7",
-            Armv7s => "armv7s",
-            Arm64 => "arm64",
-            I386 => "i386",
-            X86_64 => "x86_64",
-            X86_64_macabi => "x86_64",
-        }
-    }
-}
-
-pub fn get_sdk_root(sdk_name: &str) -> Result<String, String> {
-    // Following what clang does
-    // (https://github.com/llvm/llvm-project/blob/
-    // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678)
-    // to allow the SDK path to be set. (For clang, xcrun sets
-    // SDKROOT; for rustc, the user or build system can set it, or we
-    // can fall back to checking for xcrun on PATH.)
-    if let Ok(sdkroot) = env::var("SDKROOT") {
-        let p = Path::new(&sdkroot);
-        match sdk_name {
-            // Ignore `SDKROOT` if it's clearly set for the wrong platform.
-            "appletvos"
-                if sdkroot.contains("TVSimulator.platform")
-                    || sdkroot.contains("MacOSX.platform") => {}
-            "appletvsimulator"
-                if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {}
-            "iphoneos"
-                if sdkroot.contains("iPhoneSimulator.platform")
-                    || sdkroot.contains("MacOSX.platform") => {}
-            "iphonesimulator"
-                if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => {
-            }
-            "macosx10.15"
-                if sdkroot.contains("iPhoneOS.platform")
-                    || sdkroot.contains("iPhoneSimulator.platform") => {}
-            // Ignore `SDKROOT` if it's not a valid path.
-            _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {}
-            _ => return Ok(sdkroot),
-        }
-    }
-    let res =
-        Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then(
-            |output| {
-                if output.status.success() {
-                    Ok(String::from_utf8(output.stdout).unwrap())
-                } else {
-                    let error = String::from_utf8(output.stderr);
-                    let error = format!("process exit with error: {}", error.unwrap());
-                    Err(io::Error::new(io::ErrorKind::Other, &error[..]))
-                }
-            },
-        );
-
-    match res {
-        Ok(output) => Ok(output.trim().to_string()),
-        Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
-    }
-}
-
-fn build_pre_link_args(arch: Arch, os: AppleOS) -> Result<LinkArgs, String> {
-    let sdk_name = match (arch, os) {
-        (Arm64, AppleOS::tvOS) => "appletvos",
-        (X86_64, AppleOS::tvOS) => "appletvsimulator",
-        (Armv7, AppleOS::iOS) => "iphoneos",
-        (Armv7s, AppleOS::iOS) => "iphoneos",
-        (Arm64, AppleOS::iOS) => "iphoneos",
-        (I386, AppleOS::iOS) => "iphonesimulator",
-        (X86_64, AppleOS::iOS) => "iphonesimulator",
-        (X86_64_macabi, AppleOS::iOS) => "macosx10.15",
-        _ => unreachable!(),
-    };
-
-    let arch_name = arch.to_string();
-
-    let sdk_root = get_sdk_root(sdk_name)?;
-
-    let mut args = LinkArgs::new();
-    args.insert(
-        LinkerFlavor::Gcc,
-        vec![
-            "-arch".to_string(),
-            arch_name.to_string(),
-            "-isysroot".to_string(),
-            sdk_root.clone(),
-            "-Wl,-syslibroot".to_string(),
-            sdk_root,
-        ],
-    );
-
-    Ok(args)
-}
-
 fn target_cpu(arch: Arch) -> String {
     match arch {
         Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
@@ -137,15 +31,13 @@
     }
 }
 
-pub fn opts(arch: Arch, os: AppleOS) -> Result<TargetOptions, String> {
-    let pre_link_args = build_pre_link_args(arch, os)?;
-    Ok(TargetOptions {
+pub fn opts(arch: Arch) -> TargetOptions {
+    TargetOptions {
         cpu: target_cpu(arch),
         executables: true,
-        pre_link_args,
         link_env_remove: link_env_remove(arch),
         has_elf_tls: false,
         eliminate_frame_pointer: false,
         ..super::apple_base::opts()
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
index 7109d04..f9c6921 100644
--- a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     // https://developer.android.com/ndk/guides/abis.html#armeabi
     base.features = "+strict-align,+v5te".to_string();
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "arm-linux-androideabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
index 2e3bad8..96a444f 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
@@ -1,12 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -21,5 +21,5 @@
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
index f8e357c..534b98c 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
@@ -1,12 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -21,5 +21,5 @@
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
index 75753af..e5fa3e3 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
@@ -1,19 +1,19 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabi
     // target.
     base.features = "+strict-align,+v6".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
         // to determine the calling convention and float ABI, and it doesn't
         // support the "musleabi" value.
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
index c74c88e..b631a00 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
@@ -1,19 +1,19 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabihf
     // target.
     base.features = "+strict-align,+v6,+vfp2,-d32".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and it
         // doesn't support the "musleabihf" value.
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index e0d1f26..86d0cd5 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -1,13 +1,13 @@
 // Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armebv7r-unknown-none-eabi".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index e2d37d4..9ea44b3 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -1,13 +1,13 @@
 // Targets the Cortex-R4F/R5F processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armebv7r-unknown-none-eabihf".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -27,5 +27,5 @@
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
index 2580e8b..be32731 100644
--- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv4t-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -20,7 +20,8 @@
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            has_thumb_interworking: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
index f28421d..4ea4b65 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -20,7 +20,8 @@
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            has_thumb_interworking: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
index fe1fa88..a41a540 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and LLVM
         // doesn't support the "musleabihf" value.
         llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -23,7 +23,8 @@
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}mcount".to_string(),
+            has_thumb_interworking: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
index 1e06f83..68f6502 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::freebsd_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -21,5 +21,5 @@
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
index ef40085..23a20ca 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
@@ -1,12 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -21,5 +21,5 @@
             target_mcount: "__mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
index 3938435..24a47dd 100644
--- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::Armv7, AppleOS::iOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::Armv7);
+    Target {
         llvm_target: "armv7-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
         arch: "arm".to_string(),
@@ -20,5 +20,5 @@
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
index 38c6c31..3429598 100644
--- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target if is for the baseline of the Android v7a ABI
 // in thumb mode. It's named armv7-* instead of thumbv7-*
@@ -8,16 +8,16 @@
 // See https://developer.android.com/ndk/guides/abis.html#v7a
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.features = "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "armv7-none-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
index e3f4fe0..d4bb4e9 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "cortex-a8".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@
     base.unsupported_abis = super::arm_base::unsupported_abis();
     base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
index 80a9e6d..c32e2d4 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::freebsd_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -21,5 +21,5 @@
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
index 0f175e9..66d3b3e 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -25,5 +25,5 @@
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
index 2792345..c1ef540a 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 without NEON or
 // thumb-mode. See the thumbv7neon variant for enabling both.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
index 3d1bf05..d4d26b1 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
@@ -1,19 +1,19 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
     // Most of these settings are copied from the armv7_unknown_linux_gnueabi
     // target.
-    Ok(Target {
+    Target {
         // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
         // to determine the calling convention and float ABI, and it doesn't
         // support the "musleabi" value.
         llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -30,5 +30,5 @@
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
index 03d7d88..88db04a 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 without thumb-mode or NEON.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and LLVM
         // doesn't support the "musleabihf" value.
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -29,5 +29,5 @@
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
index 18fc9ed..fe2471a 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::netbsd_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-netbsdelf-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -22,5 +22,5 @@
             target_mcount: "__mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
index 04d8702..9b8cefd 100644
--- a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::vxworks_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -21,5 +21,5 @@
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
index 1db279d..4199ac4 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
@@ -19,7 +19,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+thumb2,+soft-float,-neon,+strict-align".to_string(),
@@ -32,10 +32,10 @@
         emit_debug_gdb_scripts: false,
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "armv7a-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -44,5 +44,5 @@
         arch: "arm".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
index 22c2b30..99a0659 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
@@ -7,7 +7,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".to_string(),
@@ -20,10 +20,10 @@
         emit_debug_gdb_scripts: false,
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "armv7a-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -32,5 +32,5 @@
         arch: "arm".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index fed8399..f0e7907 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -1,13 +1,13 @@
 // Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armv7r-unknown-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 769ac13..4c464d2 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -1,13 +1,13 @@
 // Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armv7r-unknown-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -27,5 +27,5 @@
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
index 998a7b2..4c2d70a 100644
--- a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::Armv7s, AppleOS::iOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::Armv7s);
+    Target {
         llvm_target: "armv7s-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
         arch: "arm".to_string(),
@@ -20,5 +20,5 @@
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
index d3dbc39..1c3f5c4 100644
--- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
@@ -1,12 +1,12 @@
 use super::{wasm32_unknown_emscripten, LinkerFlavor, Target};
 
-pub fn target() -> Result<Target, String> {
-    let mut target = wasm32_unknown_emscripten::target()?;
+pub fn target() -> Target {
+    let mut target = wasm32_unknown_emscripten::target();
     target
         .options
         .post_link_args
         .entry(LinkerFlavor::Em)
         .or_default()
         .extend(vec!["-s".to_string(), "WASM=0".to_string()]);
-    Ok(target)
+    target
 }
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 527a322..01445dc 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 /// A base target for AVR devices using the GNU toolchain.
 ///
 /// Requires GNU avr-gcc and avr-binutils on the host system.
-pub fn target(target_cpu: String) -> TargetResult {
-    Ok(Target {
+pub fn target(target_cpu: String) -> Target {
+    Target {
         arch: "avr".to_string(),
         data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(),
         llvm_target: "avr-unknown-unknown".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "16".to_string(),
+        pointer_width: 16,
         linker_flavor: LinkerFlavor::Gcc,
         target_os: "unknown".to_string(),
         target_env: "".to_string(),
@@ -49,5 +49,5 @@
             atomic_cas: false,
             ..TargetOptions::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs
index 5d22598..7e63ae9 100644
--- a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs
+++ b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs
@@ -1,5 +1,5 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     super::avr_gnu_base::target("atmega328".to_owned())
 }
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index c7062e1..82dc5f5 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -24,6 +24,7 @@
         pre_link_args: args,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index d2a087a..051325a 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -26,6 +26,7 @@
         eliminate_frame_pointer: false, // FIXME 43575
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
index 0976acb..143b93d 100644
--- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkArgs, LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkArgs, LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "hexagonv60".to_string();
     base.max_atomic_width = Some(32);
@@ -17,10 +17,10 @@
     base.pre_link_args = LinkArgs::new();
     base.post_link_args = LinkArgs::new();
 
-    Ok(Target {
+    Target {
         llvm_target: "hexagon-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: concat!(
             "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32",
@@ -35,5 +35,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index a121d49..2142149 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::I386, AppleOS::iOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::I386);
+    Target {
         llvm_target: "i386-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
@@ -17,5 +17,5 @@
         target_vendor: "apple".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
index ba712ac..664b9d5 100644
--- a/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
@@ -1,8 +1,8 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
-    let mut base = super::i686_pc_windows_msvc::target()?;
+pub fn target() -> Target {
+    let mut base = super::i686_pc_windows_msvc::target();
     base.options.cpu = "pentium".to_string();
     base.llvm_target = "i586-pc-windows-msvc".to_string();
-    Ok(base)
+    base
 }
diff --git a/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
index 49f4f2c..3276f1d 100644
--- a/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
@@ -1,8 +1,8 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
-    let mut base = super::i686_unknown_linux_gnu::target()?;
+pub fn target() -> Target {
+    let mut base = super::i686_unknown_linux_gnu::target();
     base.options.cpu = "pentium".to_string();
     base.llvm_target = "i586-unknown-linux-gnu".to_string();
-    Ok(base)
+    base
 }
diff --git a/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
index 0f2cceb..5fbf048 100644
--- a/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
@@ -1,8 +1,8 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
-    let mut base = super::i686_unknown_linux_musl::target()?;
+pub fn target() -> Target {
+    let mut base = super::i686_unknown_linux_musl::target();
     base.options.cpu = "pentium".to_string();
     base.llvm_target = "i586-unknown-linux-musl".to_string();
-    Ok(base)
+    base
 }
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index b7a34f9..9c7e724 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "yonah".to_string();
     base.max_atomic_width = Some(64);
@@ -15,10 +15,10 @@
     let arch = "i686";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
-    Ok(Target {
+    Target {
         llvm_target,
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
@@ -29,5 +29,5 @@
         target_vendor: "apple".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index 79242f2..d116ae6 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -1,9 +1,9 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
 // See https://developer.android.com/ndk/guides/abis.html#x86
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
 
     base.max_atomic_width = Some(64);
@@ -13,10 +13,10 @@
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -27,5 +27,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
index 33c9008..84585bd 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.pre_link_args
@@ -16,10 +16,10 @@
         .unwrap()
         .push("-Wl,--large-address-aware".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
@@ -30,5 +30,5 @@
         target_vendor: "pc".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
index 9d0922b..db20b60 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -20,10 +20,10 @@
         .unwrap()
         .extend(pre_link_args_msvc);
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
@@ -34,5 +34,5 @@
         target_vendor: "pc".to_string(),
         linker_flavor: LinkerFlavor::Msvc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
index 729b1f6..d9365d5 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-cloudabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -22,5 +22,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
index 60f2188..ba379a4 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -9,10 +9,10 @@
     pre_link_args.push("-Wl,-znotext".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-freebsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -23,5 +23,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
index 4dc27af..02754b3 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::haiku_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-haiku".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -21,5 +21,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
index 0d578f2..b7ceaef 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -21,5 +21,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index 699a0ab..9240b56 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -22,10 +22,10 @@
     // https://llvm.org/bugs/show_bug.cgi?id=30879
     base.eliminate_frame_pointer = false;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -36,5 +36,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
index 88b1ae7..a442192 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-netbsdelf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -21,5 +21,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
index 829cd1a..fe5030f 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-openbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -22,5 +22,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
index 221d5f0..676a8ca 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
@@ -5,9 +5,9 @@
 // The cdecl ABI is used. It differs from the stdcall or fastcall ABI.
 // "i686-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -76,10 +76,10 @@
     // As a result, we choose -gnu for i686 version before those intrisics are implemented in
     // compiler-builtins. After compiler-builtins implements all required intrinsics, we may
     // remove -gnu and use the default one.
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
@@ -91,5 +91,5 @@
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
 
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
index 1c6d2e0..ec5a9cc 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.pre_link_args
@@ -15,10 +15,10 @@
         .unwrap()
         .push("-Wl,--large-address-aware".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
@@ -29,5 +29,5 @@
         target_vendor: "uwp".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
index ed2dba5..d960a13 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
@@ -20,5 +20,5 @@
         target_vendor: "uwp".to_string(),
         linker_flavor: LinkerFlavor::Msvc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
index f5f66ca..0e5c7b6 100644
--- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
@@ -21,5 +21,5 @@
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs
index 52892fc..7ad972b 100644
--- a/compiler/rustc_target/src/spec/linux_base.rs
+++ b/compiler/rustc_target/src/spec/linux_base.rs
@@ -28,6 +28,7 @@
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         has_elf_tls: true,
+        crt_static_respected: true,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/linux_musl_base.rs b/compiler/rustc_target/src/spec/linux_musl_base.rs
index b90e91d..16cc3b7 100644
--- a/compiler/rustc_target/src/spec/linux_musl_base.rs
+++ b/compiler/rustc_target/src/spec/linux_musl_base.rs
@@ -10,8 +10,6 @@
 
     // These targets statically link libc by default
     base.crt_static_default = true;
-    // These targets allow the user to choose between static and dynamic linking.
-    base.crt_static_respected = true;
 
     base
 }
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
index b2ea8a6..5cbd6bc 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips64-unknown-linux-gnuabi64".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
@@ -21,5 +21,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
index 17584de..3ca92dd 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips64r2".to_string();
     base.features = "+mips64r2".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
index 48aea4a3..4761be5 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
@@ -21,5 +21,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
index c7a849a..d87170b 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips64r2".to_string();
     base.features = "+mips64r2".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64el-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
index e360abd..e51cf3c 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -20,5 +20,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
index c8d97e6..44d136e 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips32r2".to_string();
     base.features = "+mips32r2,+soft-float".to_string();
     base.max_atomic_width = Some(32);
     base.crt_static_default = false;
-    Ok(Target {
+    Target {
         llvm_target: "mips-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
index 8116b8c..7e168836 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips-unknown-linux-uclibc".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -20,5 +20,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
index b3bda97..9897b00 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -1,17 +1,17 @@
 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
 // The PSP has custom linker requirements.
 const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld");
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut pre_link_args = LinkArgs::new();
     pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["--emit-relocs".to_string()]);
 
-    Ok(Target {
+    Target {
         llvm_target: "mipsel-sony-psp".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -36,5 +36,5 @@
             link_script: Some(LINKER_SCRIPT.to_string()),
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
index 7e9d8cd..509f3e0 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsel-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -21,5 +21,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
index f70cc13..0d3691d 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips32r2".to_string();
     base.features = "+mips32r2,+soft-float".to_string();
     base.max_atomic_width = Some(32);
     base.crt_static_default = false;
-    Ok(Target {
+    Target {
         llvm_target: "mipsel-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
index a815201..6d50d9b 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsel-unknown-linux-uclibc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -21,5 +21,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
index 36b83c6..d6e71d2 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa32r6-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -20,5 +20,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
index 717ae3f..67e97fd 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa32r6el-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
@@ -21,5 +21,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
index 3f7d233..c3a7ae8 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
@@ -21,5 +21,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
index 4f41b83..467e05a 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
@@ -21,5 +21,5 @@
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f1e8330..1d3e61c 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -430,48 +430,23 @@
     }
 }
 
-pub enum LoadTargetError {
-    BuiltinTargetNotFound(String),
-    Other(String),
-}
-
 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
-pub type TargetResult = Result<Target, String>;
 
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
 
         /// List of supported targets
-        const TARGETS: &[&str] = &[$($($triple),+),+];
+        pub const TARGETS: &[&str] = &[$($($triple),+),+];
 
-        fn load_specific(target: &str) -> Result<Target, LoadTargetError> {
-            match target {
-                $(
-                    $($triple)|+ => {
-                        let mut t = $module::target()
-                            .map_err(LoadTargetError::Other)?;
-                        t.options.is_builtin = true;
-
-                        // round-trip through the JSON parser to ensure at
-                        // run-time that the parser works correctly
-                        t = Target::from_json(t.to_json())
-                            .map_err(LoadTargetError::Other)?;
-                        debug!("got builtin target: {:?}", t);
-                        Ok(t)
-                    },
-                )+
-                    _ => Err(LoadTargetError::BuiltinTargetNotFound(
-                        format!("Unable to find target: {}", target)))
-            }
-        }
-
-        pub fn get_targets() -> impl Iterator<Item = String> {
-            TARGETS.iter().filter_map(|t| -> Option<String> {
-                load_specific(t)
-                    .and(Ok(t.to_string()))
-                    .ok()
-            })
+        fn load_builtin(target: &str) -> Option<Target> {
+            let mut t = match target {
+                $( $($triple)|+ => $module::target(), )+
+                _ => return None,
+            };
+            t.options.is_builtin = true;
+            debug!("got builtin target: {:?}", t);
+            Some(t)
         }
 
         #[cfg(test)]
@@ -690,8 +665,8 @@
     pub llvm_target: String,
     /// String to use as the `target_endian` `cfg` variable.
     pub target_endian: String,
-    /// String to use as the `target_pointer_width` `cfg` variable.
-    pub target_pointer_width: String,
+    /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable.
+    pub pointer_width: u32,
     /// Width of c_int type
     pub target_c_int_width: String,
     /// OS name to use for conditional compilation.
@@ -841,6 +816,9 @@
     pub is_like_emscripten: bool,
     /// Whether the target toolchain is like Fuchsia's.
     pub is_like_fuchsia: bool,
+    /// Version of DWARF to use if not using the default.
+    /// Useful because some platforms (osx, bsd) only want up to DWARF2.
+    pub dwarf_version: Option<u32>,
     /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
     pub linker_is_gnu: bool,
     /// The MinGW toolchain has a known issue that prevents it from correctly
@@ -994,6 +972,10 @@
     /// used to locate unwinding information is passed
     /// (only has effect if the linker is `ld`-like).
     pub eh_frame_header: bool,
+
+    /// Is true if the target is an ARM architecture using thumb v1 which allows for
+    /// thumb and arm interworking.
+    pub has_thumb_interworking: bool,
 }
 
 impl Default for TargetOptions {
@@ -1033,6 +1015,7 @@
             is_like_emscripten: false,
             is_like_msvc: false,
             is_like_fuchsia: false,
+            dwarf_version: None,
             linker_is_gnu: false,
             allows_weak_linkage: true,
             has_rpath: false,
@@ -1086,6 +1069,7 @@
             llvm_args: vec![],
             use_ctors_section: false,
             eh_frame_header: true,
+            has_thumb_interworking: false,
         }
     }
 }
@@ -1127,7 +1111,7 @@
     /// Maximum integer size in bits that this target can perform atomic
     /// operations on.
     pub fn max_atomic_width(&self) -> u64 {
-        self.options.max_atomic_width.unwrap_or_else(|| self.target_pointer_width.parse().unwrap())
+        self.options.max_atomic_width.unwrap_or_else(|| self.pointer_width.into())
     }
 
     pub fn is_abi_supported(&self, abi: Abi) -> bool {
@@ -1135,7 +1119,7 @@
     }
 
     /// Loads a target descriptor from a JSON object.
-    pub fn from_json(obj: Json) -> TargetResult {
+    pub fn from_json(obj: Json) -> Result<Target, String> {
         // While ugly, this code must remain this way to retain
         // compatibility with existing JSON fields and the internal
         // expected naming of the Target and TargetOptions structs.
@@ -1160,7 +1144,9 @@
         let mut base = Target {
             llvm_target: get_req_field("llvm-target")?,
             target_endian: get_req_field("target-endian")?,
-            target_pointer_width: get_req_field("target-pointer-width")?,
+            pointer_width: get_req_field("target-pointer-width")?
+                .parse::<u32>()
+                .map_err(|_| "target-pointer-width must be an integer".to_string())?,
             target_c_int_width: get_req_field("target-c-int-width")?,
             data_layout: get_req_field("data-layout")?,
             arch: get_req_field("arch")?,
@@ -1185,6 +1171,15 @@
                     base.options.$key_name = s;
                 }
             } );
+            ($key_name:ident, Option<u32>) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
+                    if s < 1 || s > 5 {
+                        return Err("Not a valid DWARF version number".to_string());
+                    }
+                    base.options.$key_name = Some(s as u32);
+                }
+            } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
@@ -1437,6 +1432,7 @@
         key!(is_like_emscripten, bool);
         key!(is_like_android, bool);
         key!(is_like_fuchsia, bool);
+        key!(dwarf_version, Option<u32>);
         key!(linker_is_gnu, bool);
         key!(allows_weak_linkage, bool);
         key!(has_rpath, bool);
@@ -1479,6 +1475,7 @@
         key!(llvm_args, list);
         key!(use_ctors_section, bool);
         key!(eh_frame_header, bool);
+        key!(has_thumb_interworking, bool);
 
         // NB: The old name is deprecated, but support for it is retained for
         // compatibility.
@@ -1531,11 +1528,9 @@
 
         match *target_triple {
             TargetTriple::TargetTriple(ref target_triple) => {
-                // check if triple is in list of supported targets
-                match load_specific(target_triple) {
-                    Ok(t) => return Ok(t),
-                    Err(LoadTargetError::BuiltinTargetNotFound(_)) => (),
-                    Err(LoadTargetError::Other(e)) => return Err(e),
+                // check if triple is in list of built-in targets
+                if let Some(t) = load_builtin(target_triple) {
+                    return Ok(t);
                 }
 
                 // search for a file named `target_triple`.json in RUST_TARGET_PATH
@@ -1624,7 +1619,7 @@
 
         target_val!(llvm_target);
         target_val!(target_endian);
-        target_val!(target_pointer_width);
+        d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
         target_val!(target_c_int_width);
         target_val!(arch);
         target_val!(target_os, "os");
@@ -1675,6 +1670,7 @@
         target_option_val!(is_like_emscripten);
         target_option_val!(is_like_android);
         target_option_val!(is_like_fuchsia);
+        target_option_val!(dwarf_version);
         target_option_val!(linker_is_gnu);
         target_option_val!(allows_weak_linkage);
         target_option_val!(has_rpath);
@@ -1717,6 +1713,7 @@
         target_option_val!(llvm_args);
         target_option_val!(use_ctors_section);
         target_option_val!(eh_frame_header);
+        target_option_val!(has_thumb_interworking);
 
         if default.unsupported_abis != self.options.unsupported_abis {
             d.insert(
diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs
index f756979..5bb8109 100644
--- a/compiler/rustc_target/src/spec/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "msp430-none-elf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "16".to_string(),
+        pointer_width: 16,
         target_c_int_width: "16".to_string(),
         data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".to_string(),
         arch: "msp430".to_string(),
@@ -60,5 +60,5 @@
 
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 988346a..d7baf81 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -24,6 +24,7 @@
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         use_ctors_section: true,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 0c8f2a3..86360c1 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -1,10 +1,8 @@
 use crate::spec::abi::Abi;
-use crate::spec::{
-    LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions, TargetResult,
-};
+use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         arch: "nvptx64".to_string(),
         data_layout: "e-i64:64-i128:128-v16:16-v32:32-n16:32:64".to_string(),
         llvm_target: "nvptx64-nvidia-cuda".to_string(),
@@ -16,7 +14,7 @@
         linker_flavor: LinkerFlavor::PtxLinker,
 
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
 
         options: TargetOptions {
@@ -71,5 +69,5 @@
 
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index cadd14d..92a382e 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -26,6 +26,7 @@
         position_independent_executables: true,
         eliminate_frame_pointer: false, // FIXME 43575
         relro_level: RelroLevel::Full,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 60c15d6..563ff96 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-freebsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index 5306d90..7d37670 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
@@ -10,10 +10,10 @@
     // for now. https://github.com/rust-lang/rust/pull/43170#issuecomment-315411474
     base.relro_level = RelroLevel::Partial;
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
@@ -22,5 +22,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index c3b956e..e108d75 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index e00a927..9784c63 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
index 9073799..46d847f 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64le".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
index 1a1fccf..e04ee01 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "ppc64le".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64le-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
index 2d4c598..80fc63e 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index fabc431..612d296 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
index 240cbcb..fd89262 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
index 6ca7053..d33258d 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-netbsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
index 2211dc2..6a12f4c 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { features: "+secure-plt".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
index b10182c..5fee61f 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
@@ -22,5 +22,5 @@
             features: "+secure-plt,+msync".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
index 28710c6..415d7c5 100644
--- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "riscv32-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_env: "gnu".to_string(),
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
@@ -21,5 +21,5 @@
             max_atomic_width: Some(32),
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
index 5b5e342..022768f 100644
--- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         llvm_target: "riscv32".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -28,5 +28,5 @@
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
index 4cef5c4..13f0d42 100644
--- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         llvm_target: "riscv32".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -28,5 +28,5 @@
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
index 8ad563e..86189c2 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         llvm_target: "riscv32".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -28,5 +28,5 @@
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
index f7a93c9..808d715 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "riscv64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_env: "gnu".to_string(),
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
@@ -21,5 +21,5 @@
             max_atomic_width: Some(64),
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
index 3aeb3f3..0211bc0 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
         llvm_target: "riscv64".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -29,5 +29,5 @@
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
index d814496..1050ce5 100644
--- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
@@ -1,12 +1,12 @@
-use crate::spec::{CodeModel, Target, TargetOptions, TargetResult};
+use crate::spec::{CodeModel, Target, TargetOptions};
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
         llvm_target: "riscv64".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -29,5 +29,5 @@
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
index f259787..653b836 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     // z10 is the oldest CPU supported by LLVM
     base.cpu = "z10".to_string();
@@ -11,10 +11,10 @@
     base.max_atomic_width = Some(64);
     base.min_global_align = Some(16);
 
-    Ok(Target {
+    Target {
         llvm_target: "s390x-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(),
         arch: "s390x".to_string(),
@@ -23,5 +23,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
index c842b22..e50c114 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc64-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         arch: "sparc64".to_string(),
@@ -17,5 +17,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
index aad85e8..6d8e433 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "v9".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc64-unknown-netbsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         arch: "sparc64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
index 229e062..45700e1 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "v9".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc64-unknown-openbsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         arch: "sparc64".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
index 162cd31..fc400dd 100644
--- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".to_string(),
         arch: "sparc".to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
index acc03fd..0878e7f 100644
--- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::solaris_base::opts();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     // llvm calls this "v9"
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparcv9-sun-solaris".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         // Use "sparc64" instead of "sparcv9" here, since the former is already
@@ -23,5 +23,5 @@
         target_vendor: "sun".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index b2c2b82..d06ab36 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -1,16 +1,9 @@
 use super::super::*;
 
-pub(super) fn test_target(target: TargetResult) {
-    // Grab the TargetResult struct. If we successfully retrieved
-    // a Target, then the test JSON encoding/decoding can run for this
-    // Target on this testing platform (i.e., checking the iOS targets
-    // only on a Mac test platform).
-    if let Ok(original) = target {
-        original.check_consistency();
-        let as_json = original.to_json();
-        let parsed = Target::from_json(as_json).unwrap();
-        assert_eq!(original, parsed);
-    }
+// Test target self-consistency and JSON encoding/decoding roundtrip.
+pub(super) fn test_target(target: Target) {
+    target.check_consistency();
+    assert_eq!(Target::from_json(target.to_json()), Ok(target));
 }
 
 impl Target {
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index a8c78f0..d5ce62d 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -8,13 +8,13 @@
 //!
 //! **Important:** This target profile **does not** specify a linker script. You just get the default link script when you build a binary for this target. The default link script is very likely wrong, so you should use `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
 
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv4t-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: "".to_string(),
@@ -55,8 +55,9 @@
 
             // don't have atomic compare-and-swap
             atomic_cas: false,
+            has_thumb_interworking: true,
 
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
index 953d60f..407fa61 100644
--- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv6m-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -24,5 +24,5 @@
             atomic_cas: false,
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
index 3782802..d34f42c 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
 
     // Prevent error LNK2013: BRANCH24(T) fixup overflow
@@ -21,10 +21,10 @@
     // implemented for windows/arm in LLVM
     base.panic_strategy = PanicStrategy::Abort;
 
-    Ok(Target {
+    Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -40,5 +40,5 @@
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
index 29a4a98..143a9a4 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
@@ -9,10 +9,10 @@
     // implemented for windows/arm in LLVM
     base.panic_strategy = PanicStrategy::Abort;
 
-    Ok(Target {
+    Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
index 9e08538..e0b0046 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
@@ -9,13 +9,13 @@
 // To opt-in to hardware accelerated floating point operations, you can use, for example,
 // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv7em-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -25,5 +25,5 @@
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
index 95b9b9d..eecd75e 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
@@ -8,13 +8,13 @@
 //
 // To opt into double precision hardware support, use the `-C target-feature=+fp64` flag.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv7em-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -37,5 +37,5 @@
             max_atomic_width: Some(32),
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
index 528359f..a02100e 100644
--- a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M3 processor (ARMv7-M)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv7m-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -16,5 +16,5 @@
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
index c52f077..35e7d48 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target if is for the Android v7a ABI in thumb mode with
 // NEON unconditionally enabled and, therefore, with 32 FPU registers
@@ -8,16 +8,16 @@
 // See https://developer.android.com/ndk/guides/abis.html#v7a
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.features = "+v7,+thumb-mode,+thumb2,+vfp3,+neon".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "armv7-none-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
index 7893694..946b0db 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -6,12 +6,12 @@
 // registers enabled as well. See section A2.6.2 on page A2-56 in
 // https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -28,5 +28,5 @@
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
index f759c3e..91945f9 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -6,15 +6,15 @@
 // registers enabled as well. See section A2.6.2 on page A2-56 in
 // https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and LLVM
         // doesn't support the "musleabihf" value.
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -33,5 +33,5 @@
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
index 3f67c67..3833464 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M23 processor (Baseline ARMv8-M)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv8m.base-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -22,5 +22,5 @@
             max_atomic_width: Some(32),
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
index 2f8103f..3d0fb66 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
@@ -1,13 +1,13 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // without the Floating Point extension.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv8m.main-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -17,5 +17,5 @@
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
index 53a3402..82368cb 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
@@ -1,13 +1,13 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // with the Floating Point extension.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv8m.main-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
@@ -26,5 +26,5 @@
             max_atomic_width: Some(32),
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 1916639..aea0641 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -1,7 +1,7 @@
 use super::wasm32_base;
 use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let mut post_link_args = LinkArgs::new();
     post_link_args.insert(
         LinkerFlavor::Em,
@@ -28,10 +28,10 @@
         target_family: Some("unix".to_string()),
         ..wasm32_base::options()
     };
-    Ok(Target {
+    Target {
         llvm_target: "wasm32-unknown-emscripten".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "emscripten".to_string(),
         target_env: String::new(),
@@ -40,5 +40,5 @@
         arch: "wasm32".to_string(),
         linker_flavor: LinkerFlavor::Em,
         options: opts,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index ded95a3..19609b0 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -13,7 +13,7 @@
 use super::wasm32_base;
 use super::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let mut options = wasm32_base::options();
     let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
 
@@ -30,10 +30,10 @@
         .unwrap()
         .push("--no-entry".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "wasm32-unknown-unknown".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "unknown".to_string(),
         target_env: String::new(),
@@ -42,5 +42,5 @@
         arch: "wasm32".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
         options,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index 3511671..26e0722 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -75,7 +75,7 @@
 use super::wasm32_base;
 use super::{crt_objects, LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let mut options = wasm32_base::options();
 
     options
@@ -104,10 +104,10 @@
     // `args::args()` makes the WASI API calls itself.
     options.main_needs_argc_argv = false;
 
-    Ok(Target {
+    Target {
         llvm_target: "wasm32-wasi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "wasi".to_string(),
         target_env: String::new(),
@@ -116,5 +116,5 @@
         arch: "wasm32".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
         options,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 0234ff5..98e42f6 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -11,6 +11,10 @@
             "-fno-use-linker-plugin".to_string(),
             // Always enable DEP (NX bit) when it is available
             "-Wl,--nxcompat".to_string(),
+            // Enable ASLR
+            "-Wl,--dynamicbase".to_string(),
+            // ASLR will rebase it anyway so leaving that option enabled only leads to confusion
+            "-Wl,--disable-auto-image-base".to_string(),
         ],
     );
 
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index 909aebe..2b39fec 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "core2".to_string();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
@@ -18,10 +18,10 @@
     let arch = "x86_64";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
-    Ok(Target {
+    Target {
         llvm_target,
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -31,5 +31,5 @@
         target_vendor: "apple".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index cfcf856..685e046 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::X86_64, AppleOS::iOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::X86_64);
+    Target {
         llvm_target: "x86_64-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -16,5 +16,5 @@
         target_vendor: "apple".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index c42d091..ff73315 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::X86_64_macabi, AppleOS::iOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::X86_64_macabi);
+    Target {
         llvm_target: "x86_64-apple-ios13.0-macabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -16,5 +16,5 @@
         target_vendor: "apple".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index a56062c..7c0a819 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -1,12 +1,12 @@
-use super::apple_sdk_base::{opts, AppleOS, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    let base = opts(Arch::X86_64, AppleOS::iOS)?;
-    Ok(Target {
+pub fn target() -> Target {
+    let base = opts(Arch::X86_64);
+    Target {
         llvm_target: "x86_64-apple-tvos".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
         arch: "x86_64".to_string(),
@@ -15,5 +15,5 @@
         target_vendor: "apple".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
index 3b5233a..8f1627d 100644
--- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
@@ -2,7 +2,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     const PRE_LINK_ARGS: &[&str] = &[
         "--as-needed",
         "-z",
@@ -74,10 +74,10 @@
         relax_elf_relocations: true,
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-elf".into(),
         target_endian: "little".into(),
-        target_pointer_width: "64".into(),
+        pointer_width: 64,
         target_c_int_width: "32".into(),
         target_os: "unknown".into(),
         target_env: "sgx".into(),
@@ -87,5 +87,5 @@
         arch: "x86_64".into(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
index 37b6d57..71add0a 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-fuchsia".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -19,5 +19,5 @@
         target_vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
index 74097f5..aa5e48c 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.cpu = "x86-64".to_string();
     // https://developer.android.com/ndk/guides/abis.html#86-64
@@ -9,10 +9,10 @@
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -22,5 +22,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
index 65bb97d..2431675 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
@@ -1,9 +1,9 @@
 // This defines the amd64 target for the Linux Kernel. See the linux-kernel-base module for
 // generic Linux kernel options.
 
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_kernel_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -13,11 +13,11 @@
     base.code_model = Some(CodeModel::Kernel);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
-    Ok(Target {
+    Target {
         // FIXME: Some dispute, the linux-on-clang folks think this should use "Linux"
         llvm_target: "x86_64-elf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -28,5 +28,5 @@
         linker_flavor: LinkerFlavor::Gcc,
 
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
index 99af483..3b2edc9 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
@@ -1,18 +1,21 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_gnu_base::opts();
     base.cpu = "x86-64".to_string();
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+    let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
+    gcc_pre_link_args.push("-m64".to_string());
+    // Use high-entropy 64 bit address space for ASLR
+    gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string());
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]);
     base.max_atomic_width = Some(64);
     base.linker = Some("x86_64-w64-mingw32-gcc".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -22,5 +25,5 @@
         target_vendor: "pc".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs
index 75ff6b9..f21b059 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -19,5 +19,5 @@
         target_vendor: "pc".to_string(),
         linker_flavor: LinkerFlavor::Msvc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
index fbade02..2e009d7 100644
--- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
@@ -13,10 +13,10 @@
     base.disable_redzone = true;
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-rumprun-netbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -26,5 +26,5 @@
         target_vendor: "rumprun".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
index 53f4df9..aef0615 100644
--- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::solaris_base::opts();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "sun".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
index dbc5f96..bdaab88 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-cloudabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -21,5 +21,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
index fd1871b..13a62d5 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::dragonfly_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-dragonfly".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
index a124f58..1459830 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-freebsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
index 5123769..d88812e 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::haiku_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -9,10 +9,10 @@
     // This option is required to build executables on Haiku x86_64
     base.position_independent_executables = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-haiku".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -22,5 +22,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
index 4a526f9..a500209 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.features = "+rdrnd,+rdseed".to_string();
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
index c25cd08..91d7b0e 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::hermit_kernel_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -9,10 +9,10 @@
             .to_string();
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -22,5 +22,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
index 2567ca4..e49f009 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
@@ -1,17 +1,17 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::illumos_base::opts();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string(), "-std=c99".to_string()]);
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         // LLVM does not currently have a separate illumos target,
         // so we still pass Solaris to it
         llvm_target: "x86_64-pc-solaris".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -21,5 +21,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
index cab19f1..fc5b1ba 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::l4re_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -18,5 +18,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Ld,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index 29cbb77..9d9f99c 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
index 0a37399..e4a0d91 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -11,10 +11,10 @@
     // breaks code gen. See LLVM bug 36743
     base.needs_plt = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:128-n8:16:32:64-S128"
@@ -25,5 +25,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
index 3a22290..a7d3324 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@
     base.stack_probes = true;
     base.static_position_independent_executables = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -21,5 +21,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
index adf09c8..a8106c0 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
index dbd163d..5afe73e 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-openbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
index 3d40baf..e211488 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::redox_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-redox".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -20,5 +20,5 @@
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
index 849227a..894bd334 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
@@ -5,9 +5,9 @@
 // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
 // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -28,10 +28,10 @@
     // places no locality-restrictions, so it fits well here.
     base.code_model = Some(CodeModel::Large);
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-windows".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -42,5 +42,5 @@
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
 
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
index 3bd18f2..a4fa0d0 100644
--- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
@@ -1,17 +1,20 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_gnu_base::opts();
     base.cpu = "x86-64".to_string();
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+    let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
+    gcc_pre_link_args.push("-m64".to_string());
+    // Use high-entropy 64 bit address space for ASLR
+    gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string());
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]);
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -21,5 +24,5 @@
         target_vendor: "uwp".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs
index 258df01..aaf85bb 100644
--- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -19,5 +19,5 @@
         target_vendor: "uwp".to_string(),
         linker_flavor: LinkerFlavor::Msvc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
index f1e27f4..5edf7e7 100644
--- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@
     base.stack_probes = true;
     base.disable_redzone = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
@@ -21,5 +21,5 @@
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index ddeab34..406e893 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -11,6 +11,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(array_value_iter)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 28697ec..ecaafee 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -10,7 +10,7 @@
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{self, InferCtxt, InferOk};
 use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::nightly_options;
 use rustc_span::Span;
@@ -38,13 +38,13 @@
     /// then `substs` would be `['a, T]`.
     pub substs: SubstsRef<'tcx>,
 
-    /// The span of this particular definition of the opaque type.  So
+    /// The span of this particular definition of the opaque type. So
     /// for example:
     ///
-    /// ```
+    /// ```ignore (incomplete snippet)
     /// type Foo = impl Baz;
     /// fn bar() -> Foo {
-    ///             ^^^ This is the span we are looking for!
+    /// //          ^^^ This is the span we are looking for!
     /// ```
     ///
     /// In cases where the fn returns `(impl Trait, impl Trait)` or
@@ -428,14 +428,15 @@
 
         // If there are required region bounds, we can use them.
         if opaque_defn.has_required_region_bounds {
-            let predicates_of = tcx.predicates_of(def_id);
-            debug!("constrain_opaque_type: predicates: {:#?}", predicates_of,);
-            let bounds = predicates_of.instantiate(tcx, opaque_defn.substs);
+            let bounds = tcx.explicit_item_bounds(def_id);
+            debug!("constrain_opaque_type: predicates: {:#?}", bounds);
+            let bounds: Vec<_> =
+                bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect();
             debug!("constrain_opaque_type: bounds={:#?}", bounds);
             let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
 
             let required_region_bounds =
-                required_region_bounds(tcx, opaque_type, bounds.predicates.into_iter());
+                required_region_bounds(tcx, opaque_type, bounds.into_iter());
             debug_assert!(!required_region_bounds.is_empty());
 
             for required_region in required_region_bounds {
@@ -716,6 +717,8 @@
             ty::Closure(_, ref substs) => {
                 // Skip lifetime parameters of the enclosing item(s)
 
+                substs.as_closure().tupled_upvars_ty().visit_with(self);
+
                 for upvar_ty in substs.as_closure().upvar_tys() {
                     upvar_ty.visit_with(self);
                 }
@@ -727,6 +730,8 @@
                 // Skip lifetime parameters of the enclosing item(s)
                 // Also skip the witness type, because that has no free regions.
 
+                substs.as_generator().tupled_upvars_ty().visit_with(self);
+
                 for upvar_ty in substs.as_generator().upvar_tys() {
                     upvar_ty.visit_with(self);
                 }
@@ -1112,9 +1117,10 @@
         let ty_var = infcx
             .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
 
-        let predicates_of = tcx.predicates_of(def_id);
-        debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,);
-        let bounds = predicates_of.instantiate(tcx, substs);
+        let item_bounds = tcx.explicit_item_bounds(def_id);
+        debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
+        let bounds: Vec<_> =
+            item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
 
         let param_env = tcx.param_env(def_id);
         let InferOk { value: bounds, obligations } =
@@ -1123,8 +1129,7 @@
 
         debug!("instantiate_opaque_types: bounds={:?}", bounds);
 
-        let required_region_bounds =
-            required_region_bounds(tcx, ty, bounds.predicates.iter().cloned());
+        let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied());
         debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
 
         // Make sure that we are in fact defining the *entire* type
@@ -1153,7 +1158,7 @@
         );
         debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
 
-        for predicate in &bounds.predicates {
+        for predicate in &bounds {
             if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() {
                 if projection.ty.references_error() {
                     // No point on adding these obligations since there's a type error involved.
@@ -1162,14 +1167,14 @@
             }
         }
 
-        self.obligations.reserve(bounds.predicates.len());
-        for predicate in bounds.predicates {
+        self.obligations.reserve(bounds.len());
+        for predicate in bounds {
             // Change the predicate to refer to the type variable,
             // which will be the concrete type instead of the opaque type.
             // This also instantiates nested instances of `impl Trait`.
             let predicate = self.instantiate_opaque_types_in_map(&predicate);
 
-            let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType);
+            let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation);
 
             // Require that the predicate holds for the concrete type.
             debug!("instantiate_opaque_types: predicate={:?}", predicate);
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index e400672..93a0073 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -642,7 +642,8 @@
             // We check this by calling is_of_param on the relevant types
             // from the various possible predicates
 
-            match predicate.skip_binders() {
+            let bound_predicate = predicate.bound_atom();
+            match bound_predicate.skip_binder() {
                 ty::PredicateAtom::Trait(p, _) => {
                     if self.is_param_no_infer(p.trait_ref.substs)
                         && !only_projections
@@ -650,10 +651,10 @@
                     {
                         self.add_user_pred(computed_preds, predicate);
                     }
-                    predicates.push_back(ty::Binder::bind(p));
+                    predicates.push_back(bound_predicate.rebind(p));
                 }
                 ty::PredicateAtom::Projection(p) => {
-                    let p = ty::Binder::bind(p);
+                    let p = bound_predicate.rebind(p);
                     debug!(
                         "evaluate_nested_obligations: examining projection predicate {:?}",
                         predicate
@@ -783,13 +784,13 @@
                     }
                 }
                 ty::PredicateAtom::RegionOutlives(binder) => {
-                    let binder = ty::Binder::bind(binder);
+                    let binder = bound_predicate.rebind(binder);
                     if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() {
                         return false;
                     }
                 }
                 ty::PredicateAtom::TypeOutlives(binder) => {
-                    let binder = ty::Binder::bind(binder);
+                    let binder = bound_predicate.rebind(binder);
                     match (
                         binder.no_bound_vars(),
                         binder.map_bound_ref(|pred| pred.0).no_bound_vars(),
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
new file mode 100644
index 0000000..05e6c48
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -0,0 +1,129 @@
+// This file contains various trait resolution methods used by codegen.
+// They all assume regions can be erased and monomorphic types.  It
+// seems likely that they should eventually be merged into more
+// general routines.
+
+use crate::infer::{InferCtxt, TyCtxtInferExt};
+use crate::traits::{
+    FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
+    Unimplemented,
+};
+use rustc_errors::ErrorReported;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, TyCtxt};
+
+/// Attempts to resolve an obligation to a `ImplSource`. The result is
+/// a shallow `ImplSource` resolution, meaning that we do not
+/// (necessarily) resolve all nested obligations on the impl. Note
+/// that type check should guarantee to us that all nested
+/// obligations *could be* resolved if we wanted to.
+///
+/// Assumes that this is run after the entire crate has been successfully type-checked.
+/// This also expects that `trait_ref` is fully normalized.
+pub fn codegen_fulfill_obligation<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
+) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
+    // Remove any references to regions; this helps improve caching.
+    let trait_ref = tcx.erase_regions(&trait_ref);
+    // We expect the input to be fully normalized.
+    debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
+    debug!(
+        "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
+        (param_env, trait_ref),
+        trait_ref.def_id()
+    );
+
+    // Do the initial selection for the obligation. This yields the
+    // shallow result we are looking for -- that is, what specific impl.
+    tcx.infer_ctxt().enter(|infcx| {
+        let mut selcx = SelectionContext::new(&infcx);
+
+        let obligation_cause = ObligationCause::dummy();
+        let obligation =
+            Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
+
+        let selection = match selcx.select(&obligation) {
+            Ok(Some(selection)) => selection,
+            Ok(None) => {
+                // Ambiguity can happen when monomorphizing during trans
+                // expands to some humongo type that never occurred
+                // statically -- this humongo type can then overflow,
+                // leading to an ambiguous result. So report this as an
+                // overflow bug, since I believe this is the only case
+                // where ambiguity can result.
+                infcx.tcx.sess.delay_span_bug(
+                    rustc_span::DUMMY_SP,
+                    &format!(
+                        "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
+                         overflow or prior type error",
+                        trait_ref
+                    ),
+                );
+                return Err(ErrorReported);
+            }
+            Err(Unimplemented) => {
+                // This can trigger when we probe for the source of a `'static` lifetime requirement
+                // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+                infcx.tcx.sess.delay_span_bug(
+                    rustc_span::DUMMY_SP,
+                    &format!(
+                        "Encountered error `Unimplemented` selecting `{:?}` during codegen",
+                        trait_ref
+                    ),
+                );
+                return Err(ErrorReported);
+            }
+            Err(e) => {
+                bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
+            }
+        };
+
+        debug!("fulfill_obligation: selection={:?}", selection);
+
+        // Currently, we use a fulfillment context to completely resolve
+        // all nested obligations. This is because they can inform the
+        // inference of the impl's type parameters.
+        let mut fulfill_cx = FulfillmentContext::new();
+        let impl_source = selection.map(|predicate| {
+            debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
+            fulfill_cx.register_predicate_obligation(&infcx, predicate);
+        });
+        let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source);
+
+        info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
+        Ok(impl_source)
+    })
+}
+
+// # Global Cache
+
+/// Finishes processes any obligations that remain in the
+/// fulfillment context, and then returns the result with all type
+/// variables removed and regions erased. Because this is intended
+/// for use after type-check has completed, if any errors occur,
+/// it will panic. It is used during normalization and other cases
+/// where processing the obligations in `fulfill_cx` may cause
+/// type inference variables that appear in `result` to be
+/// unified, and hence we need to process those obligations to get
+/// the complete picture of the type.
+fn drain_fulfillment_cx_or_panic<T>(
+    infcx: &InferCtxt<'_, 'tcx>,
+    fulfill_cx: &mut FulfillmentContext<'tcx>,
+    result: &T,
+) -> T
+where
+    T: TypeFoldable<'tcx>,
+{
+    debug!("drain_fulfillment_cx_or_panic()");
+
+    // In principle, we only need to do this so long as `result`
+    // contains unbound type parameters. It could be a slight
+    // optimization to stop iterating early.
+    if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
+        bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
+    }
+
+    let result = infcx.resolve_vars_if_possible(result);
+    infcx.tcx.erase_regions(&result)
+}
diff --git a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs
deleted file mode 100644
index dd7ea55..0000000
--- a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-// This file contains various trait resolution methods used by codegen.
-// They all assume regions can be erased and monomorphic types.  It
-// seems likely that they should eventually be merged into more
-// general routines.
-
-use crate::infer::{InferCtxt, TyCtxtInferExt};
-use crate::traits::{
-    FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
-    Unimplemented,
-};
-use rustc_errors::ErrorReported;
-use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, TyCtxt};
-
-/// Attempts to resolve an obligation to a `ImplSource`. The result is
-/// a shallow `ImplSource` resolution, meaning that we do not
-/// (necessarily) resolve all nested obligations on the impl. Note
-/// that type check should guarantee to us that all nested
-/// obligations *could be* resolved if we wanted to.
-/// Assumes that this is run after the entire crate has been successfully type-checked.
-pub fn codegen_fulfill_obligation<'tcx>(
-    ty: TyCtxt<'tcx>,
-    (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
-) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
-    // Remove any references to regions; this helps improve caching.
-    let trait_ref = ty.erase_regions(&trait_ref);
-
-    debug!(
-        "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
-        (param_env, trait_ref),
-        trait_ref.def_id()
-    );
-
-    // Do the initial selection for the obligation. This yields the
-    // shallow result we are looking for -- that is, what specific impl.
-    ty.infer_ctxt().enter(|infcx| {
-        let mut selcx = SelectionContext::new(&infcx);
-
-        let obligation_cause = ObligationCause::dummy();
-        let obligation =
-            Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
-
-        let selection = match selcx.select(&obligation) {
-            Ok(Some(selection)) => selection,
-            Ok(None) => {
-                // Ambiguity can happen when monomorphizing during trans
-                // expands to some humongo type that never occurred
-                // statically -- this humongo type can then overflow,
-                // leading to an ambiguous result. So report this as an
-                // overflow bug, since I believe this is the only case
-                // where ambiguity can result.
-                infcx.tcx.sess.delay_span_bug(
-                    rustc_span::DUMMY_SP,
-                    &format!(
-                        "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
-                         overflow or prior type error",
-                        trait_ref
-                    ),
-                );
-                return Err(ErrorReported);
-            }
-            Err(Unimplemented) => {
-                // This can trigger when we probe for the source of a `'static` lifetime requirement
-                // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
-                infcx.tcx.sess.delay_span_bug(
-                    rustc_span::DUMMY_SP,
-                    &format!(
-                        "Encountered error `Unimplemented` selecting `{:?}` during codegen",
-                        trait_ref
-                    ),
-                );
-                return Err(ErrorReported);
-            }
-            Err(e) => {
-                bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
-            }
-        };
-
-        debug!("fulfill_obligation: selection={:?}", selection);
-
-        // Currently, we use a fulfillment context to completely resolve
-        // all nested obligations. This is because they can inform the
-        // inference of the impl's type parameters.
-        let mut fulfill_cx = FulfillmentContext::new();
-        let impl_source = selection.map(|predicate| {
-            debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
-            fulfill_cx.register_predicate_obligation(&infcx, predicate);
-        });
-        let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &impl_source);
-
-        info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
-        Ok(impl_source)
-    })
-}
-
-// # Global Cache
-
-/// Finishes processes any obligations that remain in the
-/// fulfillment context, and then returns the result with all type
-/// variables removed and regions erased. Because this is intended
-/// for use after type-check has completed, if any errors occur,
-/// it will panic. It is used during normalization and other cases
-/// where processing the obligations in `fulfill_cx` may cause
-/// type inference variables that appear in `result` to be
-/// unified, and hence we need to process those obligations to get
-/// the complete picture of the type.
-fn drain_fulfillment_cx_or_panic<T>(
-    infcx: &InferCtxt<'_, 'tcx>,
-    fulfill_cx: &mut FulfillmentContext<'tcx>,
-    result: &T,
-) -> T
-where
-    T: TypeFoldable<'tcx>,
-{
-    debug!("drain_fulfillment_cx_or_panic()");
-
-    // In principle, we only need to do this so long as `result`
-    // contains unbound type parameters. It could be a slight
-    // optimization to stop iterating early.
-    if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
-        bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
-    }
-
-    let result = infcx.resolve_vars_if_possible(result);
-    infcx.tcx.erase_regions(&result)
-}
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 0cfcaca..1e1eb16 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -23,6 +23,9 @@
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
 
+use std::cmp;
+
+/// Check if a given constant can be evaluated.
 pub fn is_const_evaluatable<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     def: ty::WithOptConstParam<DefId>,
@@ -32,24 +35,88 @@
 ) -> Result<(), ErrorHandled> {
     debug!("is_const_evaluatable({:?}, {:?})", def, substs);
     if infcx.tcx.features().const_evaluatable_checked {
-        if let Some(ct) = AbstractConst::new(infcx.tcx, def, substs)? {
-            for pred in param_env.caller_bounds() {
-                match pred.skip_binders() {
-                    ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
-                        debug!("is_const_evaluatable: caller_bound={:?}, {:?}", b_def, b_substs);
-                        if b_def == def && b_substs == substs {
-                            debug!("is_const_evaluatable: caller_bound ~~> ok");
-                            return Ok(());
-                        } else if AbstractConst::new(infcx.tcx, b_def, b_substs)?
-                            .map_or(false, |b_ct| try_unify(infcx.tcx, ct, b_ct))
-                        {
-                            debug!("is_const_evaluatable: abstract_const ~~> ok");
-                            return Ok(());
+        let tcx = infcx.tcx;
+        match AbstractConst::new(tcx, def, substs)? {
+            // We are looking at a generic abstract constant.
+            Some(ct) => {
+                for pred in param_env.caller_bounds() {
+                    match pred.skip_binders() {
+                        ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
+                            debug!(
+                                "is_const_evaluatable: caller_bound={:?}, {:?}",
+                                b_def, b_substs
+                            );
+                            if b_def == def && b_substs == substs {
+                                debug!("is_const_evaluatable: caller_bound ~~> ok");
+                                return Ok(());
+                            } else if AbstractConst::new(tcx, b_def, b_substs)?
+                                .map_or(false, |b_ct| try_unify(tcx, ct, b_ct))
+                            {
+                                debug!("is_const_evaluatable: abstract_const ~~> ok");
+                                return Ok(());
+                            }
+                        }
+                        _ => {} // don't care
+                    }
+                }
+
+                // We were unable to unify the abstract constant with
+                // a constant found in the caller bounds, there are
+                // now three possible cases here.
+                //
+                // - The substs are concrete enough that we can simply
+                //   try and evaluate the given constant.
+                // - The abstract const still references an inference
+                //   variable, in this case we return `TooGeneric`.
+                // - The abstract const references a generic parameter,
+                //   this means that we emit an error here.
+                #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+                enum FailureKind {
+                    MentionsInfer,
+                    MentionsParam,
+                    Concrete,
+                }
+                let mut failure_kind = FailureKind::Concrete;
+                walk_abstract_const(tcx, ct, |node| match node {
+                    Node::Leaf(leaf) => {
+                        let leaf = leaf.subst(tcx, ct.substs);
+                        if leaf.has_infer_types_or_consts() {
+                            failure_kind = FailureKind::MentionsInfer;
+                        } else if leaf.has_param_types_or_consts() {
+                            failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
                         }
                     }
-                    _ => {} // don't care
+                    Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => (),
+                });
+
+                match failure_kind {
+                    FailureKind::MentionsInfer => {
+                        return Err(ErrorHandled::TooGeneric);
+                    }
+                    FailureKind::MentionsParam => {
+                        // FIXME(const_evaluatable_checked): Better error message.
+                        infcx
+                            .tcx
+                            .sess
+                            .struct_span_err(span, "unconstrained generic constant")
+                            .span_help(
+                                tcx.def_span(def.did),
+                                "consider adding a `where` bound for this expression",
+                            )
+                            .emit();
+                        return Err(ErrorHandled::Reported(ErrorReported));
+                    }
+                    FailureKind::Concrete => {
+                        // Dealt with below by the same code which handles this
+                        // without the feature gate.
+                    }
                 }
             }
+            None => {
+                // If we are dealing with a concrete constant, we can
+                // reuse the old code path and try to evaluate
+                // the constant.
+            }
         }
     }
 
@@ -80,11 +147,7 @@
     if concrete.is_ok() && substs.has_param_types_or_consts() {
         match infcx.tcx.def_kind(def.did) {
             DefKind::AnonConst => {
-                let mir_body = if let Some(def) = def.as_const_arg() {
-                    infcx.tcx.optimized_mir_of_const_arg(def)
-                } else {
-                    infcx.tcx.optimized_mir(def.did)
-                };
+                let mir_body = infcx.tcx.optimized_mir_opt_const_arg(def);
 
                 if mir_body.is_polymorphic {
                     future_compat_lint();
@@ -95,7 +158,36 @@
     }
 
     debug!(?concrete, "is_const_evaluatable");
-    concrete.map(drop)
+    match concrete {
+        Err(ErrorHandled::TooGeneric) if !substs.has_infer_types_or_consts() => {
+            // FIXME(const_evaluatable_checked): We really should move
+            // emitting this error message to fulfill instead. For
+            // now this is easier.
+            //
+            // This is not a problem without `const_evaluatable_checked` as
+            // all `ConstEvaluatable` predicates have to be fulfilled for compilation
+            // to succeed.
+            //
+            // @lcnr: We already emit an error for things like
+            // `fn test<const N: usize>() -> [0 - N]` eagerly here,
+            // so until we fix this I don't really care.
+
+            let mut err = infcx
+                .tcx
+                .sess
+                .struct_span_err(span, "constant expression depends on a generic parameter");
+            // FIXME(const_generics): we should suggest to the user how they can resolve this
+            // issue. However, this is currently not actually possible
+            // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
+            //
+            // Note that with `feature(const_evaluatable_checked)` this case should not
+            // be reachable.
+            err.note("this may fail depending on what value the parameter takes");
+            err.emit();
+            Err(ErrorHandled::Reported(ErrorReported))
+        }
+        c => c.map(drop),
+    }
 }
 
 /// A tree representing an anonymous constant.
@@ -116,13 +208,7 @@
         def: ty::WithOptConstParam<DefId>,
         substs: SubstsRef<'tcx>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
-        let inner = match (def.did.as_local(), def.const_param_did) {
-            (Some(did), Some(param_did)) => {
-                tcx.mir_abstract_const_of_const_arg((did, param_did))?
-            }
-            _ => tcx.mir_abstract_const(def.did)?,
-        };
-
+        let inner = tcx.mir_abstract_const_opt_const_arg(def)?;
         Ok(inner.map(|inner| AbstractConst { inner, substs }))
     }
 
@@ -421,6 +507,33 @@
     // on `ErrorReported`.
 }
 
+fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F)
+where
+    F: FnMut(Node<'tcx>),
+{
+    recurse(tcx, ct, &mut f);
+    fn recurse<'tcx>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, f: &mut dyn FnMut(Node<'tcx>)) {
+        let root = ct.root();
+        f(root);
+        match root {
+            Node::Leaf(_) => (),
+            Node::Binop(_, l, r) => {
+                recurse(tcx, ct.subtree(l), f);
+                recurse(tcx, ct.subtree(r), f);
+            }
+            Node::UnaryOp(_, v) => {
+                recurse(tcx, ct.subtree(v), f);
+            }
+            Node::FunctionCall(func, args) => {
+                recurse(tcx, ct.subtree(func), f);
+                for &arg in args {
+                    recurse(tcx, ct.subtree(arg), f);
+                }
+            }
+        }
+    }
+}
+
 /// Tries to unify two abstract constants using structural equality.
 pub(super) fn try_unify<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 1b234a1..f8bd3ab 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -255,9 +255,10 @@
                     return;
                 }
 
-                match obligation.predicate.skip_binders() {
+                let bound_predicate = obligation.predicate.bound_atom();
+                match bound_predicate.skip_binder() {
                     ty::PredicateAtom::Trait(trait_predicate, _) => {
-                        let trait_predicate = ty::Binder::bind(trait_predicate);
+                        let trait_predicate = bound_predicate.rebind(trait_predicate);
                         let trait_predicate = self.resolve_vars_if_possible(&trait_predicate);
 
                         if self.tcx.sess.has_errors() && trait_predicate.references_error() {
@@ -531,7 +532,7 @@
                     }
 
                     ty::PredicateAtom::RegionOutlives(predicate) => {
-                        let predicate = ty::Binder::bind(predicate);
+                        let predicate = bound_predicate.rebind(predicate);
                         let predicate = self.resolve_vars_if_possible(&predicate);
                         let err = self
                             .region_outlives_predicate(&obligation.cause, predicate)
@@ -745,25 +746,9 @@
                 let violations = self.tcx.object_safety_violations(did);
                 report_object_safety_error(self.tcx, span, did, violations)
             }
-
             ConstEvalFailure(ErrorHandled::TooGeneric) => {
-                // In this instance, we have a const expression containing an unevaluated
-                // generic parameter. We have no idea whether this expression is valid or
-                // not (e.g. it might result in an error), but we don't want to just assume
-                // that it's okay, because that might result in post-monomorphisation time
-                // errors. The onus is really on the caller to provide values that it can
-                // prove are well-formed.
-                let mut err = self
-                    .tcx
-                    .sess
-                    .struct_span_err(span, "constant expression depends on a generic parameter");
-                // FIXME(const_generics): we should suggest to the user how they can resolve this
-                // issue. However, this is currently not actually possible
-                // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
-                err.note("this may fail depending on what value the parameter takes");
-                err
+                bug!("too generic should have been handled in `is_const_evaluatable`");
             }
-
             // Already reported in the query.
             ConstEvalFailure(ErrorHandled::Reported(ErrorReported)) => {
                 // FIXME(eddyb) remove this once `ErrorReported` becomes a proof token.
@@ -1094,9 +1079,10 @@
         }
 
         // FIXME: It should be possible to deal with `ForAll` in a cleaner way.
-        let (cond, error) = match (cond.skip_binders(), error.skip_binders()) {
+        let bound_error = error.bound_atom();
+        let (cond, error) = match (cond.skip_binders(), bound_error.skip_binder()) {
             (ty::PredicateAtom::Trait(..), ty::PredicateAtom::Trait(error, _)) => {
-                (cond, ty::Binder::bind(error))
+                (cond, bound_error.rebind(error))
             }
             _ => {
                 // FIXME: make this work in other cases too.
@@ -1105,9 +1091,10 @@
         };
 
         for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
-            if let ty::PredicateAtom::Trait(implication, _) = obligation.predicate.skip_binders() {
+            let bound_predicate = obligation.predicate.bound_atom();
+            if let ty::PredicateAtom::Trait(implication, _) = bound_predicate.skip_binder() {
                 let error = error.to_poly_trait_ref();
-                let implication = ty::Binder::bind(implication.trait_ref);
+                let implication = bound_predicate.rebind(implication.trait_ref);
                 // FIXME: I'm just not taking associated types at all here.
                 // Eventually I'll need to implement param-env-aware
                 // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
@@ -1185,12 +1172,13 @@
             //
             // this can fail if the problem was higher-ranked, in which
             // cause I have no idea for a good error message.
-            if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() {
+            let bound_predicate = predicate.bound_atom();
+            if let ty::PredicateAtom::Projection(data) = bound_predicate.skip_binder() {
                 let mut selcx = SelectionContext::new(self);
                 let (data, _) = self.replace_bound_vars_with_fresh_vars(
                     obligation.cause.span,
                     infer::LateBoundRegionConversionTime::HigherRankedType,
-                    &ty::Binder::bind(data),
+                    &bound_predicate.rebind(data),
                 );
                 let mut obligations = vec![];
                 let normalized_ty = super::normalize_projection_type(
@@ -1400,17 +1388,11 @@
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) {
         let get_trait_impl = |trait_def_id| {
-            let mut trait_impl = None;
-            self.tcx.for_each_relevant_impl(
+            self.tcx.find_map_relevant_impl(
                 trait_def_id,
                 trait_ref.skip_binder().self_ty(),
-                |impl_def_id| {
-                    if trait_impl.is_none() {
-                        trait_impl = Some(impl_def_id);
-                    }
-                },
-            );
-            trait_impl
+                |impl_def_id| Some(impl_def_id),
+            )
         };
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
         let all_traits = self.tcx.all_traits(LOCAL_CRATE);
@@ -1477,11 +1459,11 @@
             return;
         }
 
-        let mut err = match predicate.skip_binders() {
+        let bound_predicate = predicate.bound_atom();
+        let mut err = match bound_predicate.skip_binder() {
             ty::PredicateAtom::Trait(data, _) => {
-                let trait_ref = ty::Binder::bind(data.trait_ref);
-                let self_ty = trait_ref.skip_binder().self_ty();
-                debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind(), trait_ref);
+                let trait_ref = bound_predicate.rebind(data.trait_ref);
+                debug!("trait_ref {:?}", trait_ref);
 
                 if predicate.references_error() {
                     return;
@@ -1496,6 +1478,17 @@
                 // known, since we don't dispatch based on region
                 // relationships.
 
+                // Pick the first substitution that still contains inference variables as the one
+                // we're going to emit an error for. If there are none (see above), fall back to
+                // the substitution for `Self`.
+                let subst = {
+                    let substs = data.trait_ref.substs;
+                    substs
+                        .iter()
+                        .find(|s| s.has_infer_types_or_consts())
+                        .unwrap_or_else(|| substs[0])
+                };
+
                 // This is kind of a hack: it frequently happens that some earlier
                 // error prevents types from being fully inferred, and then we get
                 // a bunch of uninteresting errors saying something like "<generic
@@ -1512,21 +1505,11 @@
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
                 if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
-                    self.emit_inference_failure_err(
-                        body_id,
-                        span,
-                        self_ty.into(),
-                        ErrorCode::E0282,
-                    )
-                    .emit();
+                    self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0282).emit();
                     return;
                 }
-                let mut err = self.emit_inference_failure_err(
-                    body_id,
-                    span,
-                    self_ty.into(),
-                    ErrorCode::E0283,
-                );
+                let mut err =
+                    self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283);
                 err.note(&format!("cannot satisfy `{}`", predicate));
                 if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
                     self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
@@ -1604,7 +1587,7 @@
                 self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282)
             }
             ty::PredicateAtom::Projection(data) => {
-                let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx);
+                let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
                 let self_ty = trait_ref.skip_binder().self_ty();
                 let ty = data.ty;
                 if predicate.references_error() {
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 90a8d96..efa9bd6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -22,6 +22,7 @@
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_target::spec::abi;
 use std::fmt;
 
 use super::InferCtxtPrivExt;
@@ -1157,15 +1158,15 @@
                     tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
                     false,
                     hir::Unsafety::Normal,
-                    ::rustc_target::spec::abi::Abi::Rust,
+                    abi::Abi::Rust,
                 )
             } else {
                 tcx.mk_fn_sig(
-                    ::std::iter::once(inputs),
+                    std::iter::once(inputs),
                     tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
                     false,
                     hir::Unsafety::Normal,
-                    ::rustc_target::spec::abi::Abi::Rust,
+                    abi::Abi::Rust,
                 )
             };
             ty::Binder::bind(sig).to_string()
@@ -1307,6 +1308,9 @@
         let mut generator = None;
         let mut outer_generator = None;
         let mut next_code = Some(&obligation.cause.code);
+
+        let mut seen_upvar_tys_infer_tuple = false;
+
         while let Some(code) = next_code {
             debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
             match code {
@@ -1327,6 +1331,13 @@
                             outer_generator = Some(did);
                         }
                         ty::GeneratorWitness(..) => {}
+                        ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
+                            // By introducing a tuple of upvar types into the chain of obligations
+                            // of a generator, the first non-generator item is now the tuple itself,
+                            // we shall ignore this.
+
+                            seen_upvar_tys_infer_tuple = true;
+                        }
                         _ if generator.is_none() => {
                             trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
                             target_ty = Some(ty);
@@ -1907,7 +1918,34 @@
             ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
                 let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref);
                 let ty = parent_trait_ref.skip_binder().self_ty();
-                err.note(&format!("required because it appears within the type `{}`", ty));
+                if parent_trait_ref.references_error() {
+                    err.cancel();
+                    return;
+                }
+
+                // If the obligation for a tuple is set directly by a Generator or Closure,
+                // then the tuple must be the one containing capture types.
+                let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
+                    false
+                } else {
+                    if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
+                        *data.parent_code
+                    {
+                        let parent_trait_ref =
+                            self.resolve_vars_if_possible(&data.parent_trait_ref);
+                        let ty = parent_trait_ref.skip_binder().self_ty();
+                        matches!(ty.kind(), ty::Generator(..))
+                            || matches!(ty.kind(), ty::Closure(..))
+                    } else {
+                        false
+                    }
+                };
+
+                // Don't print the tuple of capture types
+                if !is_upvar_tys_infer_tuple {
+                    err.note(&format!("required because it appears within the type `{}`", ty));
+                }
+
                 obligated_types.push(ty);
 
                 let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 7e5be82..9a8b553 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,6 +1,6 @@
 use crate::infer::{InferCtxt, TyOrConstInferVar};
 use rustc_data_structures::obligation_forest::ProcessResult;
-use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
+use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
 use rustc_errors::ErrorReported;
 use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
@@ -87,7 +87,7 @@
 
 // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert_size!(PendingPredicateObligation<'_>, 64);
+static_assert_size!(PendingPredicateObligation<'_>, 56);
 
 impl<'a, 'tcx> FulfillmentContext<'tcx> {
     /// Creates a new fulfillment context.
@@ -120,7 +120,8 @@
         &mut self,
         selcx: &mut SelectionContext<'a, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
-        debug!("select(obligation-forest-size={})", self.predicates.len());
+        let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
+        let _enter = span.enter();
 
         let mut errors = Vec::new();
 
@@ -128,13 +129,11 @@
             debug!("select: starting another iteration");
 
             // Process pending obligations.
-            let outcome = self.predicates.process_obligations(
-                &mut FulfillProcessor {
+            let outcome: Outcome<_, _> =
+                self.predicates.process_obligations(&mut FulfillProcessor {
                     selcx,
                     register_region_obligations: self.register_region_obligations,
-                },
-                DoCompleted::No,
-            );
+                });
             debug!("select: outcome={:#?}", outcome);
 
             // FIXME: if we kept the original cache key, we could mark projection
@@ -173,7 +172,7 @@
         projection_ty: ty::ProjectionTy<'tcx>,
         cause: ObligationCause<'tcx>,
     ) -> Ty<'tcx> {
-        debug!("normalize_projection_type(projection_ty={:?})", projection_ty);
+        debug!(?projection_ty, "normalize_projection_type");
 
         debug_assert!(!projection_ty.has_escaping_bound_vars());
 
@@ -191,7 +190,7 @@
         );
         self.register_predicate_obligations(infcx, obligations);
 
-        debug!("normalize_projection_type: result={:?}", normalized_ty);
+        debug!(?normalized_ty);
 
         normalized_ty
     }
@@ -205,7 +204,7 @@
         // debug output much nicer to read and so on.
         let obligation = infcx.resolve_vars_if_possible(&obligation);
 
-        debug!("register_predicate_obligation(obligation={:?})", obligation);
+        debug!(?obligation, "register_predicate_obligation");
 
         assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
 
@@ -342,7 +341,7 @@
                 self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate);
         }
 
-        debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
+        debug!(?obligation, ?obligation.cause, "process_obligation");
 
         let infcx = self.selcx.infcx();
 
@@ -352,7 +351,7 @@
                 // This means we need to pass it the bound version of our
                 // predicate.
                 ty::PredicateAtom::Trait(trait_ref, _constness) => {
-                    let trait_obligation = obligation.with(Binder::bind(trait_ref));
+                    let trait_obligation = obligation.with(binder.rebind(trait_ref));
 
                     self.process_trait_obligation(
                         obligation,
@@ -361,7 +360,7 @@
                     )
                 }
                 ty::PredicateAtom::Projection(data) => {
-                    let project_obligation = obligation.with(Binder::bind(data));
+                    let project_obligation = obligation.with(binder.rebind(data));
 
                     self.process_projection_obligation(
                         project_obligation,
@@ -376,7 +375,7 @@
                 | ty::PredicateAtom::Subtype(_)
                 | ty::PredicateAtom::ConstEvaluatable(..)
                 | ty::PredicateAtom::ConstEquate(..) => {
-                    let (pred, _) = infcx.replace_bound_vars_with_placeholders(binder);
+                    let pred = infcx.replace_bound_vars_with_placeholders(binder);
                     ProcessResult::Changed(mk_pending(vec![
                         obligation.with(pred.to_predicate(self.selcx.tcx())),
                     ]))
@@ -449,6 +448,7 @@
                         self.selcx.infcx(),
                         obligation.param_env,
                         obligation.cause.body_id,
+                        obligation.recursion_depth + 1,
                         arg,
                         obligation.cause.span,
                     ) {
@@ -496,12 +496,19 @@
                         obligation.cause.span,
                     ) {
                         Ok(()) => ProcessResult::Changed(vec![]),
+                        Err(ErrorHandled::TooGeneric) => {
+                            pending_obligation.stalled_on = substs
+                                .iter()
+                                .filter_map(|ty| TyOrConstInferVar::maybe_from_generic_arg(ty))
+                                .collect();
+                            ProcessResult::Unchanged
+                        }
                         Err(e) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))),
                     }
                 }
 
                 ty::PredicateAtom::ConstEquate(c1, c2) => {
-                    debug!("equating consts: c1={:?} c2={:?}", c1, c2);
+                    debug!(?c1, ?c2, "equating consts");
                     if self.selcx.tcx().features().const_evaluatable_checked {
                         // FIXME: we probably should only try to unify abstract constants
                         // if the constants depend on generic parameters.
@@ -537,8 +544,10 @@
                                 Err(ErrorHandled::TooGeneric) => {
                                     stalled_on.append(
                                         &mut substs
-                                            .types()
-                                            .filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty))
+                                            .iter()
+                                            .filter_map(|arg| {
+                                                TyOrConstInferVar::maybe_from_generic_arg(arg)
+                                            })
                                             .collect(),
                                     );
                                     Err(ErrorHandled::TooGeneric)
@@ -591,6 +600,7 @@
         }
     }
 
+    #[instrument(level = "debug", skip(self, obligation, stalled_on))]
     fn process_trait_obligation(
         &mut self,
         obligation: &PredicateObligation<'tcx>,
@@ -603,8 +613,8 @@
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
                 debug!(
-                    "selecting trait `{:?}` at depth {} evaluated to holds",
-                    obligation.predicate, obligation.recursion_depth
+                    "selecting trait at depth {} evaluated to holds",
+                    obligation.recursion_depth
                 );
                 return ProcessResult::Changed(vec![]);
             }
@@ -612,17 +622,11 @@
 
         match self.selcx.select(&trait_obligation) {
             Ok(Some(impl_source)) => {
-                debug!(
-                    "selecting trait `{:?}` at depth {} yielded Ok(Some)",
-                    trait_obligation.predicate, obligation.recursion_depth
-                );
+                debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth);
                 ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
             }
             Ok(None) => {
-                debug!(
-                    "selecting trait `{:?}` at depth {} yielded Ok(None)",
-                    trait_obligation.predicate, obligation.recursion_depth
-                );
+                debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth);
 
                 // This is a bit subtle: for the most part, the
                 // only reason we can fail to make progress on
@@ -642,10 +646,7 @@
                 ProcessResult::Unchanged
             }
             Err(selection_err) => {
-                info!(
-                    "selecting trait `{:?}` at depth {} yielded Err",
-                    trait_obligation.predicate, obligation.recursion_depth
-                );
+                info!("selecting trait at depth {} yielded Err", obligation.recursion_depth);
 
                 ProcessResult::Error(CodeSelectionError(selection_err))
             }
@@ -663,7 +664,7 @@
             Ok(Ok(None)) => {
                 *stalled_on = trait_ref_infer_vars(
                     self.selcx,
-                    project_obligation.predicate.to_poly_trait_ref(self.selcx.tcx()),
+                    project_obligation.predicate.to_poly_trait_ref(tcx),
                 );
                 ProcessResult::Unchanged
             }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 2f2ac9f..d1647e68 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -13,7 +13,7 @@
 use crate::infer::TyCtxtInferExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{self, Obligation, ObligationCause};
-use rustc_errors::{Applicability, FatalError};
+use rustc_errors::FatalError;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
@@ -21,9 +21,10 @@
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{MultiSpan, Span};
 use smallvec::SmallVec;
 
+use std::array;
 use std::iter;
 
 pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
@@ -99,49 +100,7 @@
                 span,
             ) = violation
             {
-                // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
-                // It's also hard to get a use site span, so we use the method definition span.
-                tcx.struct_span_lint_hir(
-                    WHERE_CLAUSES_OBJECT_SAFETY,
-                    hir::CRATE_HIR_ID,
-                    *span,
-                    |lint| {
-                        let mut err = lint.build(&format!(
-                            "the trait `{}` cannot be made into an object",
-                            tcx.def_path_str(trait_def_id)
-                        ));
-                        let node = tcx.hir().get_if_local(trait_def_id);
-                        let msg = if let Some(hir::Node::Item(item)) = node {
-                            err.span_label(
-                                item.ident.span,
-                                "this trait cannot be made into an object...",
-                            );
-                            format!("...because {}", violation.error_msg())
-                        } else {
-                            format!(
-                                "the trait cannot be made into an object because {}",
-                                violation.error_msg()
-                            )
-                        };
-                        err.span_label(*span, &msg);
-                        match (node, violation.solution()) {
-                            (Some(_), Some((note, None))) => {
-                                err.help(&note);
-                            }
-                            (Some(_), Some((note, Some((sugg, span))))) => {
-                                err.span_suggestion(
-                                    span,
-                                    &note,
-                                    sugg,
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            // Only provide the help if its a local trait, otherwise it's not actionable.
-                            _ => {}
-                        }
-                        err.emit();
-                    },
-                );
+                lint_object_unsafe_trait(tcx, *span, trait_def_id, violation);
                 false
             } else {
                 true
@@ -159,6 +118,10 @@
     if !spans.is_empty() {
         violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
     }
+    let spans = bounds_reference_self(tcx, trait_def_id);
+    if !spans.is_empty() {
+        violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
+    }
 
     violations.extend(
         tcx.associated_items(trait_def_id)
@@ -175,6 +138,51 @@
     violations
 }
 
+/// Lint object-unsafe trait.
+fn lint_object_unsafe_trait(
+    tcx: TyCtxt<'_>,
+    span: Span,
+    trait_def_id: DefId,
+    violation: &ObjectSafetyViolation,
+) {
+    // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
+    // It's also hard to get a use site span, so we use the method definition span.
+    tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| {
+        let mut err = lint.build(&format!(
+            "the trait `{}` cannot be made into an object",
+            tcx.def_path_str(trait_def_id)
+        ));
+        let node = tcx.hir().get_if_local(trait_def_id);
+        let mut spans = MultiSpan::from_span(span);
+        if let Some(hir::Node::Item(item)) = node {
+            spans.push_span_label(
+                item.ident.span,
+                "this trait cannot be made into an object...".into(),
+            );
+            spans.push_span_label(span, format!("...because {}", violation.error_msg()));
+        } else {
+            spans.push_span_label(
+                span,
+                format!(
+                    "the trait cannot be made into an object because {}",
+                    violation.error_msg()
+                ),
+            );
+        };
+        err.span_note(
+            spans,
+            "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
+             call to be resolvable dynamically; for more information visit \
+             <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+        );
+        if node.is_some() {
+            // Only provide the help if its a local trait, otherwise it's not
+            violation.solution(&mut err);
+        }
+        err.emit();
+    });
+}
+
 fn sized_trait_bound_spans<'tcx>(
     tcx: TyCtxt<'tcx>,
     bounds: hir::GenericBounds<'tcx>,
@@ -238,51 +246,70 @@
     } else {
         tcx.predicates_of(trait_def_id)
     };
-    let self_ty = tcx.types.self_param;
-    let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
     predicates
         .predicates
         .iter()
-        .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
-        .filter_map(|(predicate, &sp)| {
-            match predicate.skip_binders() {
-                ty::PredicateAtom::Trait(ref data, _) => {
-                    // In the case of a trait predicate, we can skip the "self" type.
-                    if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
-                }
-                ty::PredicateAtom::Projection(ref data) => {
-                    // And similarly for projections. This should be redundant with
-                    // the previous check because any projection should have a
-                    // matching `Trait` predicate with the same inputs, but we do
-                    // the check to be safe.
-                    //
-                    // Note that we *do* allow projection *outputs* to contain
-                    // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
-                    // we just require the user to specify *both* outputs
-                    // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
-                    //
-                    // This is ALT2 in issue #56288, see that for discussion of the
-                    // possible alternatives.
-                    if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
-                        Some(sp)
-                    } else {
-                        None
-                    }
-                }
-                ty::PredicateAtom::WellFormed(..)
-                | ty::PredicateAtom::ObjectSafe(..)
-                | ty::PredicateAtom::TypeOutlives(..)
-                | ty::PredicateAtom::RegionOutlives(..)
-                | ty::PredicateAtom::ClosureKind(..)
-                | ty::PredicateAtom::Subtype(..)
-                | ty::PredicateAtom::ConstEvaluatable(..)
-                | ty::PredicateAtom::ConstEquate(..)
-                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
-            }
-        })
+        .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
+        .filter_map(|predicate| predicate_references_self(tcx, predicate))
         .collect()
 }
 
+fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
+    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
+    tcx.associated_items(trait_def_id)
+        .in_definition_order()
+        .filter(|item| item.kind == ty::AssocKind::Type)
+        .flat_map(|item| tcx.explicit_item_bounds(item.def_id))
+        .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
+        .filter_map(|predicate| predicate_references_self(tcx, predicate))
+        .collect()
+}
+
+fn predicate_references_self(
+    tcx: TyCtxt<'tcx>,
+    (predicate, sp): (ty::Predicate<'tcx>, Span),
+) -> Option<Span> {
+    let self_ty = tcx.types.self_param;
+    let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
+    match predicate.skip_binders() {
+        ty::PredicateAtom::Trait(ref data, _) => {
+            // In the case of a trait predicate, we can skip the "self" type.
+            if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
+        }
+        ty::PredicateAtom::Projection(ref data) => {
+            // And similarly for projections. This should be redundant with
+            // the previous check because any projection should have a
+            // matching `Trait` predicate with the same inputs, but we do
+            // the check to be safe.
+            //
+            // It's also won't be redundant if we allow type-generic associated
+            // types for trait objects.
+            //
+            // Note that we *do* allow projection *outputs* to contain
+            // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
+            // we just require the user to specify *both* outputs
+            // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
+            //
+            // This is ALT2 in issue #56288, see that for discussion of the
+            // possible alternatives.
+            if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
+                Some(sp)
+            } else {
+                None
+            }
+        }
+        ty::PredicateAtom::WellFormed(..)
+        | ty::PredicateAtom::ObjectSafe(..)
+        | ty::PredicateAtom::TypeOutlives(..)
+        | ty::PredicateAtom::RegionOutlives(..)
+        | ty::PredicateAtom::ClosureKind(..)
+        | ty::PredicateAtom::Subtype(..)
+        | ty::PredicateAtom::ConstEvaluatable(..)
+        | ty::PredicateAtom::ConstEquate(..)
+        | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+    }
+}
+
 fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
     generics_require_sized_self(tcx, trait_def_id)
 }
@@ -361,6 +388,8 @@
     trait_def_id: DefId,
     method: &ty::AssocItem,
 ) -> Option<MethodViolationCode> {
+    let sig = tcx.fn_sig(method.def_id);
+
     // The method's first parameter must be named `self`
     if !method.fn_has_self_parameter {
         // We'll attempt to provide a structured suggestion for `Self: Sized`.
@@ -371,11 +400,21 @@
                     [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()),
                 },
             );
-        return Some(MethodViolationCode::StaticMethod(sugg));
+        // Get the span pointing at where the `self` receiver should be.
+        let sm = tcx.sess.source_map();
+        let self_span = method.ident.span.to(tcx
+            .hir()
+            .span_if_local(method.def_id)
+            .unwrap_or_else(|| sm.next_point(method.ident.span))
+            .shrink_to_hi());
+        let self_span = sm.span_through_char(self_span, '(').shrink_to_hi();
+        return Some(MethodViolationCode::StaticMethod(
+            sugg,
+            self_span,
+            !sig.inputs().skip_binder().is_empty(),
+        ));
     }
 
-    let sig = tcx.fn_sig(method.def_id);
-
     for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
         if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
             return Some(MethodViolationCode::ReferencesSelfInput(i));
@@ -652,8 +691,7 @@
         let caller_bounds: Vec<Predicate<'tcx>> = param_env
             .caller_bounds()
             .iter()
-            .chain(iter::once(unsize_predicate))
-            .chain(iter::once(trait_predicate))
+            .chain(array::IntoIter::new([unsize_predicate, trait_predicate]))
             .collect();
 
         ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index ef8f7b6..827b1d3 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1,6 +1,5 @@
 //! Code for projecting associated types out of trait references.
 
-use super::elaborate_predicates;
 use super::specialization_graph;
 use super::translate_substs;
 use super::util;
@@ -29,7 +28,6 @@
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::symbol::sym;
-use rustc_span::DUMMY_SP;
 
 pub use rustc_middle::traits::Reveal;
 
@@ -53,13 +51,16 @@
 
 #[derive(PartialEq, Eq, Debug)]
 enum ProjectionTyCandidate<'tcx> {
-    // from a where-clause in the env or object type
+    /// From a where-clause in the env or object type
     ParamEnv(ty::PolyProjectionPredicate<'tcx>),
 
-    // from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
+    /// From the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
     TraitDef(ty::PolyProjectionPredicate<'tcx>),
 
-    // from a "impl" (or a "pseudo-impl" returned by select)
+    /// Bounds specified on an object type
+    Object(ty::PolyProjectionPredicate<'tcx>),
+
+    /// From a "impl" (or a "pseudo-impl" returned by select)
     Select(Selection<'tcx>),
 }
 
@@ -156,6 +157,7 @@
 ///    the given obligations. If the projection cannot be normalized because
 ///    the required trait bound doesn't hold this returned with `obligations`
 ///    being a predicate that cannot be proven.
+#[instrument(level = "debug", skip(selcx))]
 pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &PolyProjectionObligation<'tcx>,
@@ -163,11 +165,9 @@
     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
     MismatchedProjectionTypes<'tcx>,
 > {
-    debug!("poly_project_and_unify_type(obligation={:?})", obligation);
-
     let infcx = selcx.infcx();
     infcx.commit_if_ok(|_snapshot| {
-        let (placeholder_predicate, _) =
+        let placeholder_predicate =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
@@ -190,7 +190,7 @@
     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
     MismatchedProjectionTypes<'tcx>,
 > {
-    debug!("project_and_unify_type(obligation={:?})", obligation);
+    debug!(?obligation, "project_and_unify_type");
 
     let mut obligations = vec![];
     let normalized_ty = match opt_normalize_projection_type(
@@ -206,10 +206,7 @@
         Err(InProgress) => return Ok(Err(InProgress)),
     };
 
-    debug!(
-        "project_and_unify_type: normalized_ty={:?} obligations={:?}",
-        normalized_ty, obligations
-    );
+    debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
 
     let infcx = selcx.infcx();
     match infcx
@@ -274,6 +271,7 @@
     Normalized { value, obligations }
 }
 
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
 pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -285,16 +283,10 @@
 where
     T: TypeFoldable<'tcx>,
 {
-    debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
     let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
     let result = ensure_sufficient_stack(|| normalizer.fold(value));
-    debug!(
-        "normalize_with_depth: depth={} result={:?} with {} obligations",
-        depth,
-        result,
-        normalizer.obligations.len()
-    );
-    debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations);
+    debug!(?result, obligations.len = normalizer.obligations.len());
+    debug!(?normalizer.obligations,);
     result
 }
 
@@ -395,12 +387,11 @@
                     &mut self.obligations,
                 );
                 debug!(
-                    "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \
-                     now with {} obligations",
-                    self.depth,
-                    ty,
-                    normalized_ty,
-                    self.obligations.len()
+                    ?self.depth,
+                    ?ty,
+                    ?normalized_ty,
+                    obligations.len = ?self.obligations.len(),
+                    "AssocTypeNormalizer: normalized type"
                 );
                 normalized_ty
             }
@@ -472,6 +463,7 @@
 /// often immediately appended to another obligations vector. So now this
 /// 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))]
 fn opt_normalize_projection_type<'a, 'b, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -485,13 +477,6 @@
     let projection_ty = infcx.resolve_vars_if_possible(&projection_ty);
     let cache_key = ProjectionCacheKey::new(projection_ty);
 
-    debug!(
-        "opt_normalize_projection_type(\
-         projection_ty={:?}, \
-         depth={})",
-        projection_ty, depth
-    );
-
     // 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
     // the case of ambiguity. Which means we may create a large stream
@@ -507,10 +492,7 @@
             // If we found ambiguity the last time, that means we will continue
             // to do so until some type in the key changes (and we know it
             // hasn't, because we just fully resolved it).
-            debug!(
-                "opt_normalize_projection_type: \
-                 found cache entry: ambiguous"
-            );
+            debug!("found cache entry: ambiguous");
             return Ok(None);
         }
         Err(ProjectionCacheEntry::InProgress) => {
@@ -528,10 +510,7 @@
             // with `A::B`, which can trigger a recursive
             // normalization.
 
-            debug!(
-                "opt_normalize_projection_type: \
-                 found cache entry: in-progress"
-            );
+            debug!("found cache entry: in-progress");
 
             return Err(InProgress);
         }
@@ -547,11 +526,7 @@
             // discarded as duplicated). But when doing trait
             // evaluation this is not the case, and dropping the trait
             // evaluations can causes ICEs (e.g., #43132).
-            debug!(
-                "opt_normalize_projection_type: \
-                 found normalized ty `{:?}`",
-                ty
-            );
+            debug!(?ty, "found normalized ty");
 
             // Once we have inferred everything we need to know, we
             // can ignore the `obligations` from that point on.
@@ -561,21 +536,10 @@
             } else {
                 obligations.extend(ty.obligations);
             }
-
-            obligations.push(get_paranoid_cache_value_obligation(
-                infcx,
-                param_env,
-                projection_ty,
-                cause,
-                depth,
-            ));
             return Ok(Some(ty.value));
         }
         Err(ProjectionCacheEntry::Error) => {
-            debug!(
-                "opt_normalize_projection_type: \
-                 found error"
-            );
+            debug!("opt_normalize_projection_type: found error");
             let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
             obligations.extend(result.obligations);
             return Ok(Some(result.value));
@@ -593,13 +557,7 @@
             // an impl, where-clause etc) and hence we must
             // re-normalize it
 
-            debug!(
-                "opt_normalize_projection_type: \
-                 projected_ty={:?} \
-                 depth={} \
-                 projected_obligations={:?}",
-                projected_ty, depth, projected_obligations
-            );
+            debug!(?projected_ty, ?depth, ?projected_obligations);
 
             let result = if projected_ty.has_projections() {
                 let mut normalizer = AssocTypeNormalizer::new(
@@ -611,11 +569,7 @@
                 );
                 let normalized_ty = normalizer.fold(&projected_ty);
 
-                debug!(
-                    "opt_normalize_projection_type: \
-                     normalized_ty={:?} depth={}",
-                    normalized_ty, depth
-                );
+                debug!(?normalized_ty, ?depth);
 
                 Normalized { value: normalized_ty, obligations: projected_obligations }
             } else {
@@ -628,21 +582,14 @@
             Ok(Some(result.value))
         }
         Ok(ProjectedTy::NoProgress(projected_ty)) => {
-            debug!(
-                "opt_normalize_projection_type: \
-                 projected_ty={:?} no progress",
-                projected_ty
-            );
+            debug!(?projected_ty, "opt_normalize_projection_type: no progress");
             let result = Normalized { value: projected_ty, obligations: vec![] };
             infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
             // No need to extend `obligations`.
             Ok(Some(result.value))
         }
         Err(ProjectionTyError::TooManyCandidates) => {
-            debug!(
-                "opt_normalize_projection_type: \
-                 too many candidates"
-            );
+            debug!("opt_normalize_projection_type: too many candidates");
             infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
             Ok(None)
         }
@@ -676,7 +623,8 @@
         .obligations
         .iter()
         .filter(|obligation| {
-            match obligation.predicate.skip_binders() {
+            let bound_predicate = obligation.predicate.bound_atom();
+            match bound_predicate.skip_binder() {
                 // We found a `T: Foo<X = U>` predicate, let's check
                 // if `U` references any unresolved type
                 // variables. In principle, we only care if this
@@ -687,7 +635,7 @@
                 // but we have `T: Foo<X = ?1>` and `?1: Bar<X =
                 // ?0>`).
                 ty::PredicateAtom::Projection(data) => {
-                    infcx.unresolved_type_vars(&ty::Binder::bind(data.ty)).is_some()
+                    infcx.unresolved_type_vars(&bound_predicate.rebind(data.ty)).is_some()
                 }
 
                 // We are only interested in `T: Foo<X = U>` predicates, whre
@@ -703,45 +651,6 @@
     NormalizedTy { value: result.value, obligations }
 }
 
-/// Whenever we give back a cache result for a projection like `<T as
-/// Trait>::Item ==> X`, we *always* include the obligation to prove
-/// that `T: Trait` (we may also include some other obligations). This
-/// may or may not be necessary -- in principle, all the obligations
-/// that must be proven to show that `T: Trait` were also returned
-/// when the cache was first populated. But there are some vague concerns,
-/// and so we take the precautionary measure of including `T: Trait` in
-/// the result:
-///
-/// Concern #1. The current setup is fragile. Perhaps someone could
-/// have failed to prove the concerns from when the cache was
-/// populated, but also not have used a snapshot, in which case the
-/// cache could remain populated even though `T: Trait` has not been
-/// shown. In this case, the "other code" is at fault -- when you
-/// project something, you are supposed to either have a snapshot or
-/// else prove all the resulting obligations -- but it's still easy to
-/// get wrong.
-///
-/// Concern #2. Even within the snapshot, if those original
-/// obligations are not yet proven, then we are able to do projections
-/// that may yet turn out to be wrong. This *may* lead to some sort
-/// of trouble, though we don't have a concrete example of how that
-/// can occur yet. But it seems risky at best.
-fn get_paranoid_cache_value_obligation<'a, 'tcx>(
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    projection_ty: ty::ProjectionTy<'tcx>,
-    cause: ObligationCause<'tcx>,
-    depth: usize,
-) -> PredicateObligation<'tcx> {
-    let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
-    Obligation {
-        cause,
-        recursion_depth: depth,
-        param_env,
-        predicate: trait_ref.without_const().to_predicate(infcx.tcx),
-    }
-}
-
 /// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
 /// hold. In various error cases, we cannot generate a valid
 /// normalized projection. Therefore, we create an inference variable
@@ -801,15 +710,12 @@
 
     fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
         debug!(
-            "with_addl_obligations: self.obligations.len={} obligations.len={}",
-            self.obligations.len(),
-            obligations.len()
+            self.obligations.len = ?self.obligations.len(),
+            obligations.len = obligations.len(),
+            "with_addl_obligations"
         );
 
-        debug!(
-            "with_addl_obligations: self.obligations={:?} obligations={:?}",
-            self.obligations, obligations
-        );
+        debug!(?self.obligations, ?obligations, "with_addl_obligations");
 
         self.obligations.append(&mut obligations);
         self
@@ -824,7 +730,7 @@
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
 ) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> {
-    debug!("project(obligation={:?})", obligation);
+    debug!(?obligation, "project_type");
 
     if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) {
         debug!("project: overflow!");
@@ -833,7 +739,7 @@
 
     let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
 
-    debug!("project: obligation_trait_ref={:?}", obligation_trait_ref);
+    debug!(?obligation_trait_ref);
 
     if obligation_trait_ref.references_error() {
         return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
@@ -848,12 +754,21 @@
 
     assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
 
-    assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
+
+    if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
+        // Avoid normalization cycle from selection (see
+        // `assemble_candidates_from_object_ty`).
+        // FIXME(lazy_normalization): Lazy normalization should save us from
+        // having to do special case this.
+    } else {
+        assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    };
 
     match candidates {
-        ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress(
-            confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate),
-        )),
+        ProjectionTyCandidateSet::Single(candidate) => {
+            Ok(ProjectedTy::Progress(confirm_candidate(selcx, obligation, candidate)))
+        }
         ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
             selcx
                 .tcx()
@@ -884,6 +799,7 @@
         candidate_set,
         ProjectionTyCandidate::ParamEnv,
         obligation.param_env.caller_bounds().iter(),
+        false,
     );
 }
 
@@ -909,10 +825,8 @@
     // Check whether the self-type is itself a projection.
     // If so, extract what we know from the trait and try to come up with a good answer.
     let bounds = match *obligation_trait_ref.self_ty().kind() {
-        ty::Projection(ref data) => {
-            tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
-        }
-        ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
+        ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
+        ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
         ty::Infer(ty::TyVar(_)) => {
             // If the self-type is an inference variable, then it MAY wind up
             // being a projected type, so induce an ambiguity.
@@ -929,9 +843,57 @@
         candidate_set,
         ProjectionTyCandidate::TraitDef,
         bounds.iter(),
+        true,
     )
 }
 
+/// In the case of a trait object like
+/// `<dyn Iterator<Item = ()> as Iterator>::Item` we can use the existential
+/// predicate in the trait object.
+///
+/// We don't go through the select candidate for these bounds to avoid cycles:
+/// In the above case, `dyn Iterator<Item = ()>: Iterator` would create a
+/// nested obligation of `<dyn Iterator<Item = ()> as Iterator>::Item: Sized`,
+/// this then has to be normalized without having to prove
+/// `dyn Iterator<Item = ()>: Iterator` again.
+fn assemble_candidates_from_object_ty<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    obligation_trait_ref: &ty::TraitRef<'tcx>,
+    candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
+) {
+    debug!("assemble_candidates_from_object_ty(..)");
+
+    let tcx = selcx.tcx();
+
+    let self_ty = obligation_trait_ref.self_ty();
+    let object_ty = selcx.infcx().shallow_resolve(self_ty);
+    let data = match object_ty.kind() {
+        ty::Dynamic(data, ..) => data,
+        ty::Infer(ty::TyVar(_)) => {
+            // If the self-type is an inference variable, then it MAY wind up
+            // being an object type, so induce an ambiguity.
+            candidate_set.mark_ambiguous();
+            return;
+        }
+        _ => return,
+    };
+    let env_predicates = data
+        .projection_bounds()
+        .filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id)
+        .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
+
+    assemble_candidates_from_predicates(
+        selcx,
+        obligation,
+        obligation_trait_ref,
+        candidate_set,
+        ProjectionTyCandidate::Object,
+        env_predicates,
+        false,
+    );
+}
+
 fn assemble_candidates_from_predicates<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
@@ -939,37 +901,41 @@
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
     ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
     env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
+    potentially_unnormalized_candidates: bool,
 ) {
-    debug!("assemble_candidates_from_predicates(obligation={:?})", obligation);
+    debug!(?obligation, "assemble_candidates_from_predicates");
+
     let infcx = selcx.infcx();
     for predicate in env_predicates {
-        debug!("assemble_candidates_from_predicates: predicate={:?}", predicate);
+        debug!(?predicate);
+        let bound_predicate = predicate.bound_atom();
         if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() {
-            let data = ty::Binder::bind(data);
+            let data = bound_predicate.rebind(data);
             let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
 
             let is_match = same_def_id
                 && infcx.probe(|_| {
-                    let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx);
-                    let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
-                    infcx
-                        .at(&obligation.cause, obligation.param_env)
-                        .sup(obligation_poly_trait_ref, data_poly_trait_ref)
-                        .map(|InferOk { obligations: _, value: () }| {
-                            // FIXME(#32730) -- do we need to take obligations
-                            // into account in any way? At the moment, no.
-                        })
-                        .is_ok()
+                    selcx.match_projection_projections(
+                        obligation,
+                        obligation_trait_ref,
+                        &data,
+                        potentially_unnormalized_candidates,
+                    )
                 });
 
-            debug!(
-                "assemble_candidates_from_predicates: candidate={:?} \
-                 is_match={} same_def_id={}",
-                data, is_match, same_def_id
-            );
+            debug!(?data, ?is_match, ?same_def_id);
 
             if is_match {
                 candidate_set.push_candidate(ctor(data));
+
+                if potentially_unnormalized_candidates
+                    && !obligation.predicate.has_infer_types_or_consts()
+                {
+                    // HACK: Pick the first trait def candidate for a fully
+                    // inferred predicate. This is to allow duplicates that
+                    // differ only in normalization.
+                    return;
+                }
             }
         }
     }
@@ -981,6 +947,8 @@
     obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
+    debug!("assemble_candidates_from_impls");
+
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
     let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
@@ -993,7 +961,7 @@
                 return Err(());
             }
             Err(e) => {
-                debug!("assemble_candidates_from_impls: selection error {:?}", e);
+                debug!(error = ?e, "selection error");
                 candidate_set.mark_error(e);
                 return Err(());
             }
@@ -1003,9 +971,8 @@
             super::ImplSource::Closure(_)
             | super::ImplSource::Generator(_)
             | super::ImplSource::FnPointer(_)
-            | super::ImplSource::Object(_)
             | super::ImplSource::TraitAlias(_) => {
-                debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source);
+                debug!(?impl_source);
                 true
             }
             super::ImplSource::UserDefined(impl_data) => {
@@ -1051,10 +1018,9 @@
                         !poly_trait_ref.still_further_specializable()
                     } else {
                         debug!(
-                            "assemble_candidates_from_impls: not eligible due to default: \
-                             assoc_ty={} predicate={}",
-                            selcx.tcx().def_path_str(node_item.item.def_id),
-                            obligation.predicate,
+                            assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
+                            ?obligation.predicate,
+                            "assemble_candidates_from_impls: not eligible due to default",
                         );
                         false
                     }
@@ -1128,6 +1094,12 @@
                 // in `assemble_candidates_from_param_env`.
                 false
             }
+            super::ImplSource::Object(_) => {
+                // Handled by the `Object` projection candidate. See
+                // `assemble_candidates_from_object_ty` for an explanation of
+                // why we special case object types.
+                false
+            }
             super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
                 // These traits have no associated types.
                 selcx.tcx().sess.delay_span_bug(
@@ -1153,19 +1125,21 @@
 fn confirm_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate: ProjectionTyCandidate<'tcx>,
 ) -> Progress<'tcx> {
-    debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
-
+    debug!(?obligation, ?candidate, "confirm_candidate");
     let mut progress = match candidate {
         ProjectionTyCandidate::ParamEnv(poly_projection)
-        | ProjectionTyCandidate::TraitDef(poly_projection) => {
-            confirm_param_env_candidate(selcx, obligation, poly_projection)
+        | ProjectionTyCandidate::Object(poly_projection) => {
+            confirm_param_env_candidate(selcx, obligation, poly_projection, false)
+        }
+
+        ProjectionTyCandidate::TraitDef(poly_projection) => {
+            confirm_param_env_candidate(selcx, obligation, poly_projection, true)
         }
 
         ProjectionTyCandidate::Select(impl_source) => {
-            confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source)
+            confirm_select_candidate(selcx, obligation, impl_source)
         }
     };
     // When checking for cycle during evaluation, we compare predicates with
@@ -1182,7 +1156,6 @@
 fn confirm_select_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     impl_source: Selection<'tcx>,
 ) -> Progress<'tcx> {
     match impl_source {
@@ -1193,15 +1166,12 @@
         super::ImplSource::DiscriminantKind(data) => {
             confirm_discriminant_kind_candidate(selcx, obligation, data)
         }
-        super::ImplSource::Object(_) => {
-            confirm_object_candidate(selcx, obligation, obligation_trait_ref)
-        }
-        super::ImplSource::AutoImpl(..)
+        super::ImplSource::Object(_)
+        | super::ImplSource::AutoImpl(..)
         | super::ImplSource::Param(..)
         | super::ImplSource::Builtin(..)
-        | super::ImplSource::TraitAlias(..) =>
-        // we don't create Select candidates with this kind of resolution
-        {
+        | super::ImplSource::TraitAlias(..) => {
+            // we don't create Select candidates with this kind of resolution
             span_bug!(
                 obligation.cause.span,
                 "Cannot project an associated type from `{:?}`",
@@ -1211,72 +1181,6 @@
     }
 }
 
-fn confirm_object_candidate<'cx, 'tcx>(
-    selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
-) -> Progress<'tcx> {
-    let self_ty = obligation_trait_ref.self_ty();
-    let object_ty = selcx.infcx().shallow_resolve(self_ty);
-    debug!("confirm_object_candidate(object_ty={:?})", object_ty);
-    let data = match object_ty.kind() {
-        ty::Dynamic(data, ..) => data,
-        _ => span_bug!(
-            obligation.cause.span,
-            "confirm_object_candidate called with non-object: {:?}",
-            object_ty
-        ),
-    };
-    let env_predicates = data
-        .projection_bounds()
-        .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate(selcx.tcx()));
-    let env_predicate = {
-        let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
-
-        // select only those projections that are actually projecting an
-        // item with the correct name
-
-        let env_predicates = env_predicates.filter_map(|o| match o.predicate.skip_binders() {
-            ty::PredicateAtom::Projection(data)
-                if data.projection_ty.item_def_id == obligation.predicate.item_def_id =>
-            {
-                Some(ty::Binder::bind(data))
-            }
-            _ => None,
-        });
-
-        // select those with a relevant trait-ref
-        let mut env_predicates = env_predicates.filter(|data| {
-            let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx());
-            let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
-            selcx.infcx().probe(|_| {
-                selcx
-                    .infcx()
-                    .at(&obligation.cause, obligation.param_env)
-                    .sup(obligation_poly_trait_ref, data_poly_trait_ref)
-                    .is_ok()
-            })
-        });
-
-        // select the first matching one; there really ought to be one or
-        // else the object type is not WF, since an object type should
-        // include all of its projections explicitly
-        match env_predicates.next() {
-            Some(env_predicate) => env_predicate,
-            None => {
-                debug!(
-                    "confirm_object_candidate: no env-predicate \
-                     found in object type `{:?}`; ill-formed",
-                    object_ty
-                );
-                return Progress::error(selcx.tcx());
-            }
-        }
-    };
-
-    confirm_param_env_candidate(selcx, obligation, env_predicate)
-}
-
 fn confirm_generator_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
@@ -1291,10 +1195,7 @@
         &gen_sig,
     );
 
-    debug!(
-        "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}",
-        obligation, gen_sig, obligations
-    );
+    debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate");
 
     let tcx = selcx.tcx();
 
@@ -1325,7 +1226,7 @@
         }
     });
 
-    confirm_param_env_candidate(selcx, obligation, predicate)
+    confirm_param_env_candidate(selcx, obligation, predicate, false)
         .with_addl_obligations(impl_source.nested)
         .with_addl_obligations(obligations)
 }
@@ -1347,7 +1248,7 @@
         ty: self_ty.discriminant_ty(tcx),
     };
 
-    confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
 }
 
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
@@ -1384,10 +1285,7 @@
         &closure_sig,
     );
 
-    debug!(
-        "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}",
-        obligation, closure_sig, obligations
-    );
+    debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
 
     confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
         .with_addl_obligations(impl_source.nested)
@@ -1402,7 +1300,7 @@
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
 
-    debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
+    debug!(?obligation, ?fn_sig, "confirm_callable_candidate");
 
     let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None);
     let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None);
@@ -1422,13 +1320,14 @@
         ty: ret_type,
     });
 
-    confirm_param_env_candidate(selcx, obligation, predicate)
+    confirm_param_env_candidate(selcx, obligation, predicate, false)
 }
 
 fn confirm_param_env_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
     poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
+    potentially_unnormalized_candidate: bool,
 ) -> Progress<'tcx> {
     let infcx = selcx.infcx();
     let cause = &obligation.cause;
@@ -1442,8 +1341,28 @@
 
     let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
     let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
+    let mut nested_obligations = Vec::new();
+    let cache_trait_ref = if potentially_unnormalized_candidate {
+        ensure_sufficient_stack(|| {
+            normalize_with_depth_to(
+                selcx,
+                obligation.param_env,
+                obligation.cause.clone(),
+                obligation.recursion_depth + 1,
+                &cache_trait_ref,
+                &mut nested_obligations,
+            )
+        })
+    } else {
+        cache_trait_ref
+    };
+
     match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
-        Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations },
+        Ok(InferOk { value: _, obligations }) => {
+            nested_obligations.extend(obligations);
+            assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
+            Progress { ty: cache_entry.ty, obligations: nested_obligations }
+        }
         Err(e) => {
             let msg = format!(
                 "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
@@ -1463,7 +1382,7 @@
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
 
-    let ImplSourceUserDefinedData { impl_def_id, substs, nested } = impl_impl_source;
+    let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source;
     let assoc_item_id = obligation.predicate.item_def_id;
     let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
 
@@ -1496,15 +1415,48 @@
     let ty = tcx.type_of(assoc_ty.item.def_id);
     if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
         let err = tcx.ty_error_with_message(
-            DUMMY_SP,
+            obligation.cause.span,
             "impl item and trait item have different parameter counts",
         );
         Progress { ty: err, obligations: nested }
     } else {
+        assoc_ty_own_obligations(selcx, obligation, &mut nested);
         Progress { ty: ty.subst(tcx, substs), obligations: nested }
     }
 }
 
+// Get obligations corresponding to the predicates from the where-clause of the
+// associated type itself.
+// Note: `feature(generic_associated_types)` is required to write such
+// predicates, even for non-generic associcated types.
+fn assoc_ty_own_obligations<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    nested: &mut Vec<PredicateObligation<'tcx>>,
+) {
+    let tcx = selcx.tcx();
+    for predicate in tcx
+        .predicates_of(obligation.predicate.item_def_id)
+        .instantiate_own(tcx, obligation.predicate.substs)
+        .predicates
+    {
+        let normalized = normalize_with_depth_to(
+            selcx,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            &predicate,
+            nested,
+        );
+        nested.push(Obligation::with_depth(
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            obligation.param_env,
+            normalized,
+        ));
+    }
+}
+
 /// Locate the definition of an associated type in the specialization hierarchy,
 /// starting from the given impl.
 ///
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 424b3bd..8212823 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -110,7 +110,7 @@
         // check if *any* of those are trivial.
         ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
         ty::Closure(_, ref substs) => {
-            substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
+            trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
         }
 
         ty::Adt(def, _) => {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 3dcebbc..d748fc8 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -7,7 +7,7 @@
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::error_reporting::InferCtxtExt;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
-use rustc_data_structures::mini_map::MiniMap;
+use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::traits::Normalized;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
@@ -44,7 +44,7 @@
     {
         debug!(
             "normalize::<{}>(value={:?}, param_env={:?})",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             value,
             self.param_env,
         );
@@ -58,20 +58,20 @@
             param_env: self.param_env,
             obligations: vec![],
             error: false,
-            cache: MiniMap::new(),
+            cache: SsoHashMap::new(),
             anon_depth: 0,
         };
 
         let result = value.fold_with(&mut normalizer);
         debug!(
             "normalize::<{}>: result={:?} with {} obligations",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             result,
             normalizer.obligations.len(),
         );
         debug!(
             "normalize::<{}>: obligations={:?}",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             normalizer.obligations,
         );
         if normalizer.error {
@@ -87,7 +87,7 @@
     cause: &'cx ObligationCause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     obligations: Vec<PredicateObligation<'tcx>>,
-    cache: MiniMap<Ty<'tcx>, Ty<'tcx>>,
+    cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
     error: bool,
     anon_depth: usize,
 }
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 a494323..b0bfb4a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -7,16 +7,22 @@
 //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
 use rustc_hir as hir;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, TypeFoldable};
 use rustc_target::spec::abi::Abi;
 
+use crate::traits::coherence::Conflict;
 use crate::traits::{util, SelectionResult};
+use crate::traits::{Overflow, Unimplemented};
 
 use super::BuiltinImplConditions;
+use super::IntercrateAmbiguityCause;
+use super::OverflowError;
 use super::SelectionCandidate::{self, *};
-use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack};
+use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack};
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn candidate_from_obligation<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
@@ -30,16 +36,13 @@
         // this is because we want the unbound variables to be
         // replaced with fresh types starting from index 0.
         let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate);
-        debug!(
-            "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
-            cache_fresh_trait_pred, stack
-        );
+        debug!(?cache_fresh_trait_pred);
         debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
 
         if let Some(c) =
             self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred)
         {
-            debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c);
+            debug!(candidate = ?c, "CACHE HIT");
             return c;
         }
 
@@ -52,7 +55,7 @@
         let (candidate, dep_node) =
             self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
 
-        debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate);
+        debug!(?candidate, "CACHE MISS");
         self.insert_candidate_cache(
             stack.obligation.param_env,
             cache_fresh_trait_pred,
@@ -62,6 +65,161 @@
         candidate
     }
 
+    fn candidate_from_obligation_no_cache<'o>(
+        &mut self,
+        stack: &TraitObligationStack<'o, 'tcx>,
+    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+        if let Some(conflict) = self.is_knowable(stack) {
+            debug!("coherence stage: not knowable");
+            if self.intercrate_ambiguity_causes.is_some() {
+                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+                // Heuristics: show the diagnostics when there are no candidates in crate.
+                if let Ok(candidate_set) = self.assemble_candidates(stack) {
+                    let mut no_candidates_apply = true;
+
+                    for c in candidate_set.vec.iter() {
+                        if self.evaluate_candidate(stack, &c)?.may_apply() {
+                            no_candidates_apply = false;
+                            break;
+                        }
+                    }
+
+                    if !candidate_set.ambiguous && no_candidates_apply {
+                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+                        let self_ty = trait_ref.self_ty();
+                        let (trait_desc, self_desc) = with_no_trimmed_paths(|| {
+                            let trait_desc = trait_ref.print_only_trait_path().to_string();
+                            let self_desc = if self_ty.has_concrete_skeleton() {
+                                Some(self_ty.to_string())
+                            } else {
+                                None
+                            };
+                            (trait_desc, self_desc)
+                        });
+                        let cause = if let Conflict::Upstream = conflict {
+                            IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+                        } else {
+                            IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+                        };
+                        debug!(?cause, "evaluate_stack: pushing cause");
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                    }
+                }
+            }
+            return Ok(None);
+        }
+
+        let candidate_set = self.assemble_candidates(stack)?;
+
+        if candidate_set.ambiguous {
+            debug!("candidate set contains ambig");
+            return Ok(None);
+        }
+
+        let mut candidates = candidate_set.vec;
+
+        debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
+
+        // At this point, we know that each of the entries in the
+        // candidate set is *individually* applicable. Now we have to
+        // figure out if they contain mutual incompatibilities. This
+        // frequently arises if we have an unconstrained input type --
+        // for example, we are looking for `$0: Eq` where `$0` is some
+        // unconstrained type variable. In that case, we'll get a
+        // candidate which assumes $0 == int, one that assumes `$0 ==
+        // usize`, etc. This spells an ambiguity.
+
+        // If there is more than one candidate, first winnow them down
+        // by considering extra conditions (nested obligations and so
+        // forth). We don't winnow if there is exactly one
+        // candidate. This is a relatively minor distinction but it
+        // can lead to better inference and error-reporting. An
+        // example would be if there was an impl:
+        //
+        //     impl<T:Clone> Vec<T> { fn push_clone(...) { ... } }
+        //
+        // and we were to see some code `foo.push_clone()` where `boo`
+        // is a `Vec<Bar>` and `Bar` does not implement `Clone`.  If
+        // we were to winnow, we'd wind up with zero candidates.
+        // Instead, we select the right impl now but report "`Bar` does
+        // not implement `Clone`".
+        if candidates.len() == 1 {
+            return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
+        }
+
+        // Winnow, but record the exact outcome of evaluation, which
+        // is needed for specialization. Propagate overflow if it occurs.
+        let mut candidates = candidates
+            .into_iter()
+            .map(|c| match self.evaluate_candidate(stack, &c) {
+                Ok(eval) if eval.may_apply() => {
+                    Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
+                }
+                Ok(_) => Ok(None),
+                Err(OverflowError) => Err(Overflow),
+            })
+            .flat_map(Result::transpose)
+            .collect::<Result<Vec<_>, _>>()?;
+
+        debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len());
+
+        let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
+
+        // If there are STILL multiple candidates, we can further
+        // reduce the list by dropping duplicates -- including
+        // resolving specializations.
+        if candidates.len() > 1 {
+            let mut i = 0;
+            while i < candidates.len() {
+                let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
+                    self.candidate_should_be_dropped_in_favor_of(
+                        &candidates[i],
+                        &candidates[j],
+                        needs_infer,
+                    )
+                });
+                if is_dup {
+                    debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
+                    candidates.swap_remove(i);
+                } else {
+                    debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
+                    i += 1;
+
+                    // If there are *STILL* multiple candidates, give up
+                    // and report ambiguity.
+                    if i > 1 {
+                        debug!("multiple matches, ambig");
+                        return Ok(None);
+                    }
+                }
+            }
+        }
+
+        // If there are *NO* candidates, then there are no impls --
+        // that we know of, anyway. Note that in the case where there
+        // are unbound type variables within the obligation, it might
+        // be the case that you could still satisfy the obligation
+        // from another crate by instantiating the type variables with
+        // a type from another crate that does have an impl. This case
+        // is checked for in `evaluate_stack` (and hence users
+        // who might care about this case, like coherence, should use
+        // that function).
+        if candidates.is_empty() {
+            // If there's an error type, 'downgrade' our result from
+            // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid
+            // emitting additional spurious errors, since we're guaranteed
+            // to have emitted at least one.
+            if stack.obligation.references_error() {
+                debug!("no results for error type, treating as ambiguous");
+                return Ok(None);
+            }
+            return Err(Unimplemented);
+        }
+
+        // Just one candidate left.
+        self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
+    }
+
     pub(super) fn assemble_candidates<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
@@ -97,7 +255,7 @@
         let lang_items = self.tcx().lang_items();
 
         if lang_items.copy_trait() == Some(def_id) {
-            debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty());
+            debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
 
             // User-defined copy impls are permitted, but only for
             // structs and enums.
@@ -148,7 +306,7 @@
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        debug!("assemble_candidates_for_projected_tys({:?})", obligation);
+        debug!(?obligation, "assemble_candidates_from_projected_tys");
 
         // Before we go into the whole placeholder thing, just
         // quickly check if the self-type is a projection at all.
@@ -167,8 +325,8 @@
             .infcx
             .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
 
-        if result {
-            candidates.vec.push(ProjectionCandidate);
+        for predicate_index in result {
+            candidates.vec.push(ProjectionCandidate(predicate_index));
         }
     }
 
@@ -181,7 +339,7 @@
         stack: &TraitObligationStack<'o, 'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
-        debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation);
+        debug!(?stack.obligation, "assemble_candidates_from_caller_bounds");
 
         let all_bounds = stack
             .obligation
@@ -223,10 +381,7 @@
         let self_ty = obligation.self_ty().skip_binder();
         match self_ty.kind() {
             ty::Generator(..) => {
-                debug!(
-                    "assemble_generator_candidates: self_ty={:?} obligation={:?}",
-                    self_ty, obligation
-                );
+                debug!(?self_ty, ?obligation, "assemble_generator_candidates",);
 
                 candidates.vec.push(GeneratorCandidate);
             }
@@ -263,10 +418,10 @@
         // type/region parameters
         match *obligation.self_ty().skip_binder().kind() {
             ty::Closure(_, closure_substs) => {
-                debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation);
+                debug!(?kind, ?obligation, "assemble_unboxed_candidates");
                 match self.infcx.closure_kind(closure_substs) {
                     Some(closure_kind) => {
-                        debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
+                        debug!(?closure_kind, "assemble_unboxed_candidates");
                         if closure_kind.extends(kind) {
                             candidates.vec.push(ClosureCandidate);
                         }
@@ -343,7 +498,7 @@
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
-        debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
+        debug!(?obligation, "assemble_candidates_from_impls");
 
         // Essentially any user-written impl will match with an error type,
         // so creating `ImplCandidates` isn't useful. However, we might
@@ -377,7 +532,7 @@
     ) -> Result<(), SelectionError<'tcx>> {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
-        debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
+        debug!(?self_ty, "assemble_candidates_from_auto_impls");
 
         let def_id = obligation.predicate.def_id();
 
@@ -444,8 +599,8 @@
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
         debug!(
-            "assemble_candidates_from_object_ty(self_ty={:?})",
-            obligation.self_ty().skip_binder()
+            self_ty = ?obligation.self_ty().skip_binder(),
+            "assemble_candidates_from_object_ty",
         );
 
         self.infcx.probe(|_snapshot| {
@@ -485,26 +640,32 @@
                 _ => return,
             };
 
-            debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref);
+            debug!(?poly_trait_ref, "assemble_candidates_from_object_ty");
+
+            let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
+            let placeholder_trait_predicate =
+                self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
 
             // Count only those upcast versions that match the trait-ref
             // we are looking for. Specifically, do not only check for the
             // correct trait, but also the correct type parameters.
             // For example, we may be trying to upcast `Foo` to `Bar<i32>`,
             // but `Foo` is declared as `trait Foo: Bar<u32>`.
-            let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref)
-                .filter(|upcast_trait_ref| {
-                    self.infcx
-                        .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok())
+            let candidate_supertraits = util::supertraits(self.tcx(), poly_trait_ref)
+                .enumerate()
+                .filter(|&(_, upcast_trait_ref)| {
+                    self.infcx.probe(|_| {
+                        self.match_normalize_trait_ref(
+                            obligation,
+                            upcast_trait_ref,
+                            placeholder_trait_predicate.trait_ref,
+                        )
+                        .is_ok()
+                    })
                 })
-                .count();
+                .map(|(idx, _)| ObjectCandidate(idx));
 
-            if upcast_trait_refs > 1 {
-                // Can be upcast in many ways; need more type information.
-                candidates.ambiguous = true;
-            } else if upcast_trait_refs == 1 {
-                candidates.vec.push(ObjectCandidate);
-            }
+            candidates.vec.extend(candidate_supertraits);
         })
     }
 
@@ -537,7 +698,7 @@
         };
         let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
 
-        debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target);
+        debug!(?source, ?target, "assemble_candidates_for_unsizing");
 
         let may_apply = match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
@@ -598,7 +759,7 @@
     ) -> Result<(), SelectionError<'tcx>> {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
-        debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
+        debug!(?self_ty, "assemble_candidates_for_trait_alias");
 
         let def_id = obligation.predicate.def_id();
 
@@ -618,7 +779,7 @@
     ) -> Result<(), SelectionError<'tcx>> {
         match conditions {
             BuiltinImplConditions::Where(nested) => {
-                debug!("builtin_bound: nested={:?}", nested);
+                debug!(?nested, "builtin_bound");
                 candidates
                     .vec
                     .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() });
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 88b656c..872b8e8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -10,12 +10,13 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_infer::infer::InferOk;
+use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
 use rustc_span::def_id::DefId;
 
-use crate::traits::project::{self, normalize_with_depth};
+use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::select::TraitObligationExt;
 use crate::traits::util;
 use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
@@ -41,13 +42,12 @@
 use std::iter;
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn confirm_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidate: SelectionCandidate<'tcx>,
     ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
-        debug!("confirm_candidate({:?}, {:?})", obligation, candidate);
-
         match candidate {
             BuiltinCandidate { has_nested } => {
                 let data = self.confirm_builtin_candidate(obligation, has_nested);
@@ -68,9 +68,14 @@
                 Ok(ImplSource::AutoImpl(data))
             }
 
-            ProjectionCandidate => {
-                self.confirm_projection_candidate(obligation);
-                Ok(ImplSource::Param(Vec::new()))
+            ProjectionCandidate(idx) => {
+                let obligations = self.confirm_projection_candidate(obligation, idx)?;
+                Ok(ImplSource::Param(obligations))
+            }
+
+            ObjectCandidate(idx) => {
+                let data = self.confirm_object_candidate(obligation, idx)?;
+                Ok(ImplSource::Object(data))
             }
 
             ClosureCandidate => {
@@ -97,11 +102,6 @@
                 Ok(ImplSource::TraitAlias(data))
             }
 
-            ObjectCandidate => {
-                let data = self.confirm_object_candidate(obligation);
-                Ok(ImplSource::Object(data))
-            }
-
             BuiltinObjectCandidate => {
                 // This indicates something like `Trait + Send: Send`. In this case, we know that
                 // this holds because that's what the object type is telling us, and there's really
@@ -116,10 +116,66 @@
         }
     }
 
-    fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
+    fn confirm_projection_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        idx: usize,
+    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
         self.infcx.commit_unconditionally(|_| {
-            let result = self.match_projection_obligation_against_definition_bounds(obligation);
-            assert!(result);
+            let tcx = self.tcx();
+
+            let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
+            let placeholder_trait_predicate =
+                self.infcx().replace_bound_vars_with_placeholders(&trait_predicate);
+            let placeholder_self_ty = placeholder_trait_predicate.self_ty();
+            let (def_id, substs) = match *placeholder_self_ty.kind() {
+                ty::Projection(proj) => (proj.item_def_id, proj.substs),
+                ty::Opaque(def_id, substs) => (def_id, substs),
+                _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
+            };
+
+            let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs);
+            let candidate = candidate_predicate
+                .to_opt_poly_trait_ref()
+                .expect("projection candidate is not a trait predicate");
+            let mut obligations = Vec::new();
+            let candidate = normalize_with_depth_to(
+                self,
+                obligation.param_env,
+                obligation.cause.clone(),
+                obligation.recursion_depth + 1,
+                &candidate,
+                &mut obligations,
+            );
+
+            obligations.extend(self.infcx.commit_if_ok(|_| {
+                self.infcx
+                    .at(&obligation.cause, obligation.param_env)
+                    .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate)
+                    .map(|InferOk { obligations, .. }| obligations)
+                    .map_err(|_| Unimplemented)
+            })?);
+
+            if let ty::Projection(..) = placeholder_self_ty.kind() {
+                for predicate in tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates {
+                    let normalized = normalize_with_depth_to(
+                        self,
+                        obligation.param_env,
+                        obligation.cause.clone(),
+                        obligation.recursion_depth + 1,
+                        &predicate,
+                        &mut obligations,
+                    );
+                    obligations.push(Obligation::with_depth(
+                        obligation.cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        normalized,
+                    ));
+                }
+            }
+
+            Ok(obligations)
         })
     }
 
@@ -128,7 +184,7 @@
         obligation: &TraitObligation<'tcx>,
         param: ty::PolyTraitRef<'tcx>,
     ) -> Vec<PredicateObligation<'tcx>> {
-        debug!("confirm_param_candidate({:?},{:?})", obligation, param);
+        debug!(?obligation, ?param, "confirm_param_candidate");
 
         // During evaluation, we already checked that this
         // where-clause trait-ref could be unified with the obligation
@@ -151,7 +207,7 @@
         obligation: &TraitObligation<'tcx>,
         has_nested: bool,
     ) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> {
-        debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested);
+        debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
 
         let lang_items = self.tcx().lang_items();
         let obligations = if has_nested {
@@ -184,7 +240,7 @@
             vec![]
         };
 
-        debug!("confirm_builtin_candidate: obligations={:?}", obligations);
+        debug!(?obligations);
 
         ImplSourceBuiltinData { nested: obligations }
     }
@@ -199,7 +255,7 @@
         obligation: &TraitObligation<'tcx>,
         trait_def_id: DefId,
     ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
-        debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id);
+        debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate");
 
         let types = obligation.predicate.map_bound(|inner| {
             let self_ty = self.infcx.shallow_resolve(inner.self_ty());
@@ -215,7 +271,7 @@
         trait_def_id: DefId,
         nested: ty::Binder<Vec<Ty<'tcx>>>,
     ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
-        debug!("vtable_auto_impl: nested={:?}", nested);
+        debug!(?nested, "vtable_auto_impl");
         ensure_sufficient_stack(|| {
             let cause = obligation.derived_cause(BuiltinDerivedObligation);
             let mut obligations = self.collect_predicates_for_types(
@@ -229,7 +285,7 @@
             let trait_obligations: Vec<PredicateObligation<'_>> =
                 self.infcx.commit_unconditionally(|_| {
                     let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-                    let (trait_ref, _) =
+                    let trait_ref =
                         self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref);
                     let cause = obligation.derived_cause(ImplDerivedObligation);
                     self.impl_or_trait_obligations(
@@ -245,7 +301,7 @@
             // predicate as usual.  It won't have any effect since auto traits are coinductive.
             obligations.extend(trait_obligations);
 
-            debug!("vtable_auto_impl: obligations={:?}", obligations);
+            debug!(?obligations, "vtable_auto_impl");
 
             ImplSourceAutoImplData { trait_def_id, nested: obligations }
         })
@@ -256,13 +312,13 @@
         obligation: &TraitObligation<'tcx>,
         impl_def_id: DefId,
     ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id);
+        debug!(?obligation, ?impl_def_id, "confirm_impl_candidate");
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
         self.infcx.commit_unconditionally(|_| {
             let substs = self.rematch_impl(impl_def_id, obligation);
-            debug!("confirm_impl_candidate: substs={:?}", substs);
+            debug!(?substs, "impl substs");
             let cause = obligation.derived_cause(ImplDerivedObligation);
             ensure_sufficient_stack(|| {
                 self.vtable_impl(
@@ -284,10 +340,7 @@
         recursion_depth: usize,
         param_env: ty::ParamEnv<'tcx>,
     ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
-        debug!(
-            "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})",
-            impl_def_id, substs, recursion_depth,
-        );
+        debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl");
 
         let mut impl_obligations = self.impl_or_trait_obligations(
             cause,
@@ -297,74 +350,149 @@
             &substs.value,
         );
 
-        debug!(
-            "vtable_impl: impl_def_id={:?} impl_obligations={:?}",
-            impl_def_id, impl_obligations
-        );
+        debug!(?impl_obligations, "vtable_impl");
 
         // Because of RFC447, the impl-trait-ref and obligations
         // are sufficient to determine the impl substs, without
         // relying on projections in the impl-trait-ref.
         //
         // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
-        impl_obligations.append(&mut substs.obligations);
+        substs.obligations.append(&mut impl_obligations);
 
-        ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations }
+        ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: substs.obligations }
     }
 
     fn confirm_object_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-    ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_object_candidate({:?})", obligation);
+        index: usize,
+    ) -> Result<ImplSourceObjectData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        let tcx = self.tcx();
+        debug!(?obligation, ?index, "confirm_object_candidate");
 
-        // FIXME(nmatsakis) skipping binder here seems wrong -- we should
-        // probably flatten the binder from the obligation and the binder
-        // from the object. Have to try to make a broken test case that
-        // results.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        let poly_trait_ref = match self_ty.kind() {
-            ty::Dynamic(data, ..) => data
-                .principal()
-                .unwrap_or_else(|| {
-                    span_bug!(obligation.cause.span, "object candidate with no principal")
-                })
-                .with_self_ty(self.tcx(), self_ty),
+        let trait_predicate =
+            self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
+        let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
+        let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
+        let data = match self_ty.kind() {
+            ty::Dynamic(data, ..) => {
+                self.infcx
+                    .replace_bound_vars_with_fresh_vars(
+                        obligation.cause.span,
+                        HigherRankedType,
+                        data,
+                    )
+                    .0
+            }
             _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
         };
 
-        let mut upcast_trait_ref = None;
+        let object_trait_ref = data
+            .principal()
+            .unwrap_or_else(|| {
+                span_bug!(obligation.cause.span, "object candidate with no principal")
+            })
+            .with_self_ty(self.tcx(), self_ty);
+
         let mut nested = vec![];
-        let vtable_base;
 
+        let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
+
+        // For each of the non-matching predicates that
+        // we pass over, we sum up the set of number of vtable
+        // entries, so that we can compute the offset for the selected
+        // trait.
+        let vtable_base = supertraits
+            .by_ref()
+            .take(index)
+            .map(|t| super::util::count_own_vtable_entries(tcx, t))
+            .sum();
+
+        let unnormalized_upcast_trait_ref =
+            supertraits.next().expect("supertraits iterator no longer has as many elements");
+
+        let upcast_trait_ref = normalize_with_depth_to(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            &unnormalized_upcast_trait_ref,
+            &mut nested,
+        );
+
+        nested.extend(self.infcx.commit_if_ok(|_| {
+            self.infcx
+                .at(&obligation.cause, obligation.param_env)
+                .sup(obligation_trait_ref, upcast_trait_ref)
+                .map(|InferOk { obligations, .. }| obligations)
+                .map_err(|_| Unimplemented)
+        })?);
+
+        // Check supertraits hold. This is so that their associated type bounds
+        // will be checked in the code below.
+        for super_trait in tcx
+            .super_predicates_of(trait_predicate.def_id())
+            .instantiate(tcx, trait_predicate.trait_ref.substs)
+            .predicates
+            .into_iter()
         {
-            let tcx = self.tcx();
-
-            // We want to find the first supertrait in the list of
-            // supertraits that we can unify with, and do that
-            // unification. We know that there is exactly one in the list
-            // where we can unify, because otherwise select would have
-            // reported an ambiguity. (When we do find a match, also
-            // record it for later.)
-            let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| {
-                match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) {
-                    Ok(obligations) => {
-                        upcast_trait_ref = Some(t);
-                        nested.extend(obligations);
-                        false
-                    }
-                    Err(_) => true,
-                }
-            });
-
-            // Additionally, for each of the non-matching predicates that
-            // we pass over, we sum up the set of number of vtable
-            // entries, so that we can compute the offset for the selected
-            // trait.
-            vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
+            if let ty::PredicateAtom::Trait(..) = super_trait.skip_binders() {
+                let normalized_super_trait = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    &super_trait,
+                    &mut nested,
+                );
+                nested.push(Obligation::new(
+                    obligation.cause.clone(),
+                    obligation.param_env.clone(),
+                    normalized_super_trait,
+                ));
+            }
         }
 
-        ImplSourceObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
+        let assoc_types: Vec<_> = tcx
+            .associated_items(trait_predicate.def_id())
+            .in_definition_order()
+            .filter_map(
+                |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
+            )
+            .collect();
+
+        for assoc_type in assoc_types {
+            if !tcx.generics_of(assoc_type).params.is_empty() {
+                // FIXME(generic_associated_types) generate placeholders to
+                // extend the trait substs.
+                tcx.sess.span_fatal(
+                    obligation.cause.span,
+                    "generic associated types in trait objects are not supported yet",
+                );
+            }
+            // This maybe belongs in wf, but that can't (doesn't) handle
+            // higher-ranked things.
+            // Prevent, e.g., `dyn Iterator<Item = str>`.
+            for bound in self.tcx().item_bounds(assoc_type) {
+                let subst_bound = bound.subst(tcx, trait_predicate.trait_ref.substs);
+                let normalized_bound = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    &subst_bound,
+                    &mut nested,
+                );
+                nested.push(Obligation::new(
+                    obligation.cause.clone(),
+                    obligation.param_env.clone(),
+                    normalized_bound,
+                ));
+            }
+        }
+
+        debug!(?nested, "object nested obligations");
+        Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
     }
 
     fn confirm_fn_pointer_candidate(
@@ -372,7 +500,7 @@
         obligation: &TraitObligation<'tcx>,
     ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
     {
-        debug!("confirm_fn_pointer_candidate({:?})", obligation);
+        debug!(?obligation, "confirm_fn_pointer_candidate");
 
         // Okay to skip binder; it is reintroduced below.
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
@@ -386,8 +514,8 @@
         )
         .map_bound(|(trait_ref, _)| trait_ref);
 
-        let Normalized { value: trait_ref, obligations } = ensure_sufficient_stack(|| {
-            project::normalize_with_depth(
+        let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
+            normalize_with_depth(
                 self,
                 obligation.param_env,
                 obligation.cause.clone(),
@@ -396,12 +524,12 @@
             )
         });
 
-        self.confirm_poly_trait_refs(
+        obligations.extend(self.confirm_poly_trait_refs(
             obligation.cause.clone(),
             obligation.param_env,
             obligation.predicate.to_poly_trait_ref(),
             trait_ref,
-        )?;
+        )?);
         Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested: obligations })
     }
 
@@ -410,10 +538,10 @@
         obligation: &TraitObligation<'tcx>,
         alias_def_id: DefId,
     ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id);
+        debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
 
         self.infcx.commit_unconditionally(|_| {
-            let (predicate, _) =
+            let predicate =
                 self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
             let trait_ref = predicate.trait_ref;
             let trait_def_id = trait_ref.def_id;
@@ -427,10 +555,7 @@
                 &substs,
             );
 
-            debug!(
-                "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}",
-                trait_def_id, trait_obligations
-            );
+            debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
 
             ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
         })
@@ -450,7 +575,7 @@
             _ => bug!("closure candidate for non-closure {:?}", obligation),
         };
 
-        debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs);
+        debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate");
 
         let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs);
         let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
@@ -463,11 +588,7 @@
             )
         });
 
-        debug!(
-            "confirm_generator_candidate(generator_def_id={:?}, \
-             trait_ref={:?}, obligations={:?})",
-            generator_def_id, trait_ref, obligations
-        );
+        debug!(?trait_ref, ?obligations, "generator candidate obligations");
 
         obligations.extend(self.confirm_poly_trait_refs(
             obligation.cause.clone(),
@@ -483,7 +604,7 @@
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        debug!("confirm_closure_candidate({:?})", obligation);
+        debug!(?obligation, "confirm_closure_candidate");
 
         let kind = self
             .tcx()
@@ -510,10 +631,7 @@
             )
         });
 
-        debug!(
-            "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
-            closure_def_id, trait_ref, obligations
-        );
+        debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations");
 
         obligations.extend(self.confirm_poly_trait_refs(
             obligation.cause.clone(),
@@ -587,7 +705,7 @@
         let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
         let target = self.infcx.shallow_resolve(target);
 
-        debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target);
+        debug!(?source, ?target, "confirm_builtin_unsize_candidate");
 
         let mut nested = vec![];
         match (source.kind(), target.kind()) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 57f1fed..4cc4bc0 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -9,6 +9,7 @@
 use super::const_evaluatable;
 use super::project;
 use super::project::normalize_with_depth_to;
+use super::project::ProjectionTyObligation;
 use super::util;
 use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
 use super::wf;
@@ -36,9 +37,8 @@
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
-use rustc_middle::ty::{
-    self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
-};
+use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::symbol::sym;
 
 use std::cell::{Cell, RefCell};
@@ -236,7 +236,7 @@
         infcx: &'cx InferCtxt<'cx, 'tcx>,
         allow_negative_impls: bool,
     ) -> SelectionContext<'cx, 'tcx> {
-        debug!("with_negative({:?})", allow_negative_impls);
+        debug!(?allow_negative_impls, "with_negative");
         SelectionContext {
             infcx,
             freshener: infcx.freshener(),
@@ -251,7 +251,7 @@
         infcx: &'cx InferCtxt<'cx, 'tcx>,
         query_mode: TraitQueryMode,
     ) -> SelectionContext<'cx, 'tcx> {
-        debug!("with_query_mode({:?})", query_mode);
+        debug!(?query_mode, "with_query_mode");
         SelectionContext {
             infcx,
             freshener: infcx.freshener(),
@@ -290,10 +290,6 @@
         self.infcx.tcx
     }
 
-    pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> {
-        self.infcx
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -311,11 +307,11 @@
 
     /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
     /// type environment by performing unification.
+    #[instrument(level = "debug", skip(self))]
     pub fn select(
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, Selection<'tcx>> {
-        debug!("select({:?})", obligation);
         debug_assert!(!obligation.predicate.has_escaping_bound_vars());
 
         let pec = &ProvisionalEvaluationCache::default();
@@ -343,7 +339,10 @@
                 Err(SelectionError::Overflow)
             }
             Err(e) => Err(e),
-            Ok(candidate) => Ok(Some(candidate)),
+            Ok(candidate) => {
+                debug!(?candidate);
+                Ok(Some(candidate))
+            }
         }
     }
 
@@ -359,7 +358,7 @@
 
     /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
     pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
-        debug!("predicate_may_hold_fatal({:?})", obligation);
+        debug!(?obligation, "predicate_may_hold_fatal");
 
         // This fatal query is a stopgap that should only be used in standard mode,
         // where we do not expect overflow to be propagated.
@@ -413,12 +412,12 @@
         predicates: I,
     ) -> Result<EvaluationResult, OverflowError>
     where
-        I: IntoIterator<Item = PredicateObligation<'tcx>>,
+        I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
     {
         let mut result = EvaluatedToOk;
+        debug!(?predicates, "evaluate_predicates_recursively");
         for obligation in predicates {
             let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
-            debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval);
             if let EvaluatedToErr = eval {
                 // fast-path - EvaluatedToErr is the top of the lattice,
                 // so we don't need to look on the other predicates.
@@ -430,17 +429,16 @@
         Ok(result)
     }
 
+    #[instrument(
+        level = "debug",
+        skip(self, previous_stack),
+        fields(previous_stack = ?previous_stack.head())
+    )]
     fn evaluate_predicate_recursively<'o>(
         &mut self,
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         obligation: PredicateObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        debug!(
-            "evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})",
-            previous_stack.head(),
-            obligation
-        );
-
         // `previous_stack` stores a `TraitObligation`, while `obligation` is
         // a `PredicateObligation`. These are distinct types, so we can't
         // use any `Option` combinator method that would force them to be
@@ -450,17 +448,18 @@
             None => self.check_recursion_limit(&obligation, &obligation)?,
         }
 
-        ensure_sufficient_stack(|| {
-            match obligation.predicate.skip_binders() {
+        let result = ensure_sufficient_stack(|| {
+            let bound_predicate = obligation.predicate.bound_atom();
+            match bound_predicate.skip_binder() {
                 ty::PredicateAtom::Trait(t, _) => {
-                    let t = ty::Binder::bind(t);
+                    let t = bound_predicate.rebind(t);
                     debug_assert!(!t.has_escaping_bound_vars());
                     let obligation = obligation.with(t);
                     self.evaluate_trait_predicate_recursively(previous_stack, obligation)
                 }
 
                 ty::PredicateAtom::Subtype(p) => {
-                    let p = ty::Binder::bind(p);
+                    let p = bound_predicate.rebind(p);
                     // Does this code ever run?
                     match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
                         Some(Ok(InferOk { mut obligations, .. })) => {
@@ -479,15 +478,13 @@
                     self.infcx,
                     obligation.param_env,
                     obligation.cause.body_id,
+                    obligation.recursion_depth + 1,
                     arg,
                     obligation.cause.span,
                 ) {
                     Some(mut obligations) => {
                         self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
-                        self.evaluate_predicates_recursively(
-                            previous_stack,
-                            obligations.into_iter(),
-                        )
+                        self.evaluate_predicates_recursively(previous_stack, obligations)
                     }
                     None => Ok(EvaluatedToAmbig),
                 },
@@ -506,15 +503,13 @@
                 }
 
                 ty::PredicateAtom::Projection(data) => {
-                    let data = ty::Binder::bind(data);
+                    let data = bound_predicate.rebind(data);
                     let project_obligation = obligation.with(data);
                     match project::poly_project_and_unify_type(self, &project_obligation) {
                         Ok(Ok(Some(mut subobligations))) => {
                             self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
-                            let result = self.evaluate_predicates_recursively(
-                                previous_stack,
-                                subobligations.into_iter(),
-                            );
+                            let result = self
+                                .evaluate_predicates_recursively(previous_stack, subobligations);
                             if let Some(key) =
                                 ProjectionCacheKey::from_poly_projection_predicate(self, data)
                             {
@@ -523,12 +518,7 @@
                             result
                         }
                         Ok(Ok(None)) => Ok(EvaluatedToAmbig),
-                        // EvaluatedToRecur might also be acceptable here, but use
-                        // Unknown for now because it means that we won't dismiss a
-                        // selection candidate solely because it has a projection
-                        // cycle. This is closest to the previous behavior of
-                        // immediately erroring.
-                        Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown),
+                        Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur),
                         Err(_) => Ok(EvaluatedToErr),
                     }
                 }
@@ -561,10 +551,7 @@
                 }
 
                 ty::PredicateAtom::ConstEquate(c1, c2) => {
-                    debug!(
-                        "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}",
-                        c1, c2
-                    );
+                    debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
                     let evaluate = |c: &'tcx ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
@@ -610,7 +597,11 @@
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
             }
-        })
+        });
+
+        debug!(?result);
+
+        result
     }
 
     fn evaluate_trait_predicate_recursively<'o>(
@@ -618,7 +609,7 @@
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: TraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        debug!("evaluate_trait_predicate_recursively({:?})", obligation);
+        debug!(?obligation, "evaluate_trait_predicate_recursively");
 
         if !self.intercrate
             && obligation.is_global()
@@ -627,19 +618,22 @@
             // If a param env has no global bounds, global obligations do not
             // depend on its particular value in order to work, so we can clear
             // out the param env and get better caching.
-            debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
+            debug!("evaluate_trait_predicate_recursively - in global");
             obligation.param_env = obligation.param_env.without_caller_bounds();
         }
 
         let stack = self.push_stack(previous_stack, &obligation);
         let fresh_trait_ref = stack.fresh_trait_ref;
+
+        debug!(?fresh_trait_ref);
+
         if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
-            debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
+            debug!(?result, "CACHE HIT");
             return Ok(result);
         }
 
         if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
-            debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
+            debug!(?result, "PROVISIONAL CACHE HIT");
             stack.update_reached_depth(stack.cache().current_reached_depth());
             return Ok(result);
         }
@@ -662,7 +656,7 @@
 
         let reached_depth = stack.reached_depth.get();
         if reached_depth >= stack.depth {
-            debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
+            debug!(?result, "CACHE MISS");
             self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
 
             stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| {
@@ -674,7 +668,7 @@
                 );
             });
         } else {
-            debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result);
+            debug!(?result, "PROVISIONAL");
             debug!(
                 "evaluate_trait_predicate_recursively: caching provisionally because {:?} \
                  is a cycle participant (at depth {}, reached depth {})",
@@ -719,10 +713,7 @@
             })
             .map(|stack| stack.depth)
         {
-            debug!(
-                "evaluate_stack({:?}) --> recursive at depth {}",
-                stack.fresh_trait_ref, cycle_depth,
-            );
+            debug!("evaluate_stack --> recursive at depth {}", cycle_depth);
 
             // If we have a stack like `A B C D E A`, where the top of
             // the stack is the final `A`, then this will iterate over
@@ -742,10 +733,10 @@
             let cycle =
                 cycle.map(|stack| stack.obligation.predicate.without_const().to_predicate(tcx));
             if self.coinductive_match(cycle) {
-                debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
+                debug!("evaluate_stack --> recursive, coinductive");
                 Some(EvaluatedToOk)
             } else {
-                debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref);
+                debug!("evaluate_stack --> recursive, inductive");
                 Some(EvaluatedToRecur)
             }
         } else {
@@ -786,10 +777,7 @@
         // This check was an imperfect workaround for a bug in the old
         // intercrate mode; it should be removed when that goes away.
         if unbound_input_types && self.intercrate {
-            debug!(
-                "evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
-                stack.fresh_trait_ref
-            );
+            debug!("evaluate_stack --> unbound argument, intercrate -->  ambiguous",);
             // Heuristics: show the diagnostics when there are no candidates in crate.
             if self.intercrate_ambiguity_causes.is_some() {
                 debug!("evaluate_stack: intercrate_ambiguity_causes is some");
@@ -807,7 +795,7 @@
                                 },
                             });
 
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        debug!(?cause, "evaluate_stack: pushing cause");
                         self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
                     }
                 }
@@ -824,10 +812,7 @@
                     )
             })
         {
-            debug!(
-                "evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
-                stack.fresh_trait_ref
-            );
+            debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
             return Ok(EvaluatedToUnknown);
         }
 
@@ -860,36 +845,37 @@
             ty::PredicateAtom::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
             _ => false,
         };
-        debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
+        debug!(?predicate, ?result, "coinductive_predicate");
         result
     }
 
     /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
     /// obligations are met. Returns whether `candidate` remains viable after this further
     /// scrutiny.
+    #[instrument(
+        level = "debug",
+        skip(self, stack),
+        fields(depth = stack.obligation.recursion_depth)
+    )]
     fn evaluate_candidate<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
         candidate: &SelectionCandidate<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        debug!(
-            "evaluate_candidate: depth={} candidate={:?}",
-            stack.obligation.recursion_depth, candidate
-        );
         let result = self.evaluation_probe(|this| {
             let candidate = (*candidate).clone();
             match this.confirm_candidate(stack.obligation, candidate) {
-                Ok(selection) => this.evaluate_predicates_recursively(
-                    stack.list(),
-                    selection.nested_obligations().into_iter(),
-                ),
+                Ok(selection) => {
+                    debug!(?selection);
+                    this.evaluate_predicates_recursively(
+                        stack.list(),
+                        selection.nested_obligations().into_iter(),
+                    )
+                }
                 Err(..) => Ok(EvaluatedToErr),
             }
         })?;
-        debug!(
-            "evaluate_candidate: depth={} result={:?}",
-            stack.obligation.recursion_depth, result
-        );
+        debug!(?result);
         Ok(result)
     }
 
@@ -922,10 +908,7 @@
 
         if self.can_use_global_caches(param_env) {
             if !trait_ref.needs_infer() {
-                debug!(
-                    "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global",
-                    trait_ref, result,
-                );
+                debug!(?trait_ref, ?result, "insert_evaluation_cache global");
                 // This may overwrite the cache with the same value
                 // FIXME: Due to #50507 this overwrites the different values
                 // This should be changed to use HashMapExt::insert_same
@@ -935,7 +918,7 @@
             }
         }
 
-        debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,);
+        debug!(?trait_ref, ?result, "insert_evaluation_cache");
         self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
     }
 
@@ -943,10 +926,9 @@
     /// to have a *lower* recursion_depth than the obligation used to create it.
     /// Projection sub-obligations may be returned from the projection cache,
     /// which results in obligations with an 'old' `recursion_depth`.
-    /// Additionally, methods like `wf::obligations` and
-    /// `InferCtxt.subtype_predicate` produce subobligations without
-    /// taking in a 'parent' depth, causing the generated subobligations
-    /// to have a `recursion_depth` of `0`.
+    /// Additionally, methods like `InferCtxt.subtype_predicate` produce
+    /// subobligations without taking in a 'parent' depth, causing the
+    /// generated subobligations to have a `recursion_depth` of `0`.
     ///
     /// To ensure that obligation_depth never decreasees, we force all subobligations
     /// to have at least the depth of the original obligation.
@@ -1029,161 +1011,6 @@
         Ok(Some(candidate))
     }
 
-    fn candidate_from_obligation_no_cache<'o>(
-        &mut self,
-        stack: &TraitObligationStack<'o, 'tcx>,
-    ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
-        if let Some(conflict) = self.is_knowable(stack) {
-            debug!("coherence stage: not knowable");
-            if self.intercrate_ambiguity_causes.is_some() {
-                debug!("evaluate_stack: intercrate_ambiguity_causes is some");
-                // Heuristics: show the diagnostics when there are no candidates in crate.
-                if let Ok(candidate_set) = self.assemble_candidates(stack) {
-                    let mut no_candidates_apply = true;
-
-                    for c in candidate_set.vec.iter() {
-                        if self.evaluate_candidate(stack, &c)?.may_apply() {
-                            no_candidates_apply = false;
-                            break;
-                        }
-                    }
-
-                    if !candidate_set.ambiguous && no_candidates_apply {
-                        let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
-                        let self_ty = trait_ref.self_ty();
-                        let (trait_desc, self_desc) = with_no_trimmed_paths(|| {
-                            let trait_desc = trait_ref.print_only_trait_path().to_string();
-                            let self_desc = if self_ty.has_concrete_skeleton() {
-                                Some(self_ty.to_string())
-                            } else {
-                                None
-                            };
-                            (trait_desc, self_desc)
-                        });
-                        let cause = if let Conflict::Upstream = conflict {
-                            IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
-                        } else {
-                            IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
-                        };
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
-                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
-                    }
-                }
-            }
-            return Ok(None);
-        }
-
-        let candidate_set = self.assemble_candidates(stack)?;
-
-        if candidate_set.ambiguous {
-            debug!("candidate set contains ambig");
-            return Ok(None);
-        }
-
-        let mut candidates = candidate_set.vec;
-
-        debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
-
-        // At this point, we know that each of the entries in the
-        // candidate set is *individually* applicable. Now we have to
-        // figure out if they contain mutual incompatibilities. This
-        // frequently arises if we have an unconstrained input type --
-        // for example, we are looking for `$0: Eq` where `$0` is some
-        // unconstrained type variable. In that case, we'll get a
-        // candidate which assumes $0 == int, one that assumes `$0 ==
-        // usize`, etc. This spells an ambiguity.
-
-        // If there is more than one candidate, first winnow them down
-        // by considering extra conditions (nested obligations and so
-        // forth). We don't winnow if there is exactly one
-        // candidate. This is a relatively minor distinction but it
-        // can lead to better inference and error-reporting. An
-        // example would be if there was an impl:
-        //
-        //     impl<T:Clone> Vec<T> { fn push_clone(...) { ... } }
-        //
-        // and we were to see some code `foo.push_clone()` where `boo`
-        // is a `Vec<Bar>` and `Bar` does not implement `Clone`.  If
-        // we were to winnow, we'd wind up with zero candidates.
-        // Instead, we select the right impl now but report "`Bar` does
-        // not implement `Clone`".
-        if candidates.len() == 1 {
-            return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
-        }
-
-        // Winnow, but record the exact outcome of evaluation, which
-        // is needed for specialization. Propagate overflow if it occurs.
-        let mut candidates = candidates
-            .into_iter()
-            .map(|c| match self.evaluate_candidate(stack, &c) {
-                Ok(eval) if eval.may_apply() => {
-                    Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
-                }
-                Ok(_) => Ok(None),
-                Err(OverflowError) => Err(Overflow),
-            })
-            .flat_map(Result::transpose)
-            .collect::<Result<Vec<_>, _>>()?;
-
-        debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
-
-        let needs_infer = stack.obligation.predicate.needs_infer();
-
-        // If there are STILL multiple candidates, we can further
-        // reduce the list by dropping duplicates -- including
-        // resolving specializations.
-        if candidates.len() > 1 {
-            let mut i = 0;
-            while i < candidates.len() {
-                let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
-                    self.candidate_should_be_dropped_in_favor_of(
-                        &candidates[i],
-                        &candidates[j],
-                        needs_infer,
-                    )
-                });
-                if is_dup {
-                    debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
-                    candidates.swap_remove(i);
-                } else {
-                    debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
-                    i += 1;
-
-                    // If there are *STILL* multiple candidates, give up
-                    // and report ambiguity.
-                    if i > 1 {
-                        debug!("multiple matches, ambig");
-                        return Ok(None);
-                    }
-                }
-            }
-        }
-
-        // If there are *NO* candidates, then there are no impls --
-        // that we know of, anyway. Note that in the case where there
-        // are unbound type variables within the obligation, it might
-        // be the case that you could still satisfy the obligation
-        // from another crate by instantiating the type variables with
-        // a type from another crate that does have an impl. This case
-        // is checked for in `evaluate_stack` (and hence users
-        // who might care about this case, like coherence, should use
-        // that function).
-        if candidates.is_empty() {
-            // If there's an error type, 'downgrade' our result from
-            // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid
-            // emitting additional spurious errors, since we're guaranteed
-            // to have emitted at least one.
-            if stack.obligation.references_error() {
-                debug!("no results for error type, treating as ambiguous");
-                return Ok(None);
-            }
-            return Err(Unimplemented);
-        }
-
-        // Just one candidate left.
-        self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
-    }
-
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
         debug!("is_knowable(intercrate={:?})", self.intercrate);
 
@@ -1280,11 +1107,7 @@
         let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
 
         if !self.can_cache_candidate(&candidate) {
-            debug!(
-                "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\
-                 candidate is not cacheable",
-                trait_ref, candidate
-            );
+            debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
             return;
         }
 
@@ -1293,10 +1116,7 @@
                 // Don't cache overflow globally; we only produce this in certain modes.
             } else if !trait_ref.needs_infer() {
                 if !candidate.needs_infer() {
-                    debug!(
-                        "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global",
-                        trait_ref, candidate,
-                    );
+                    debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
                     // This may overwrite the cache with the same value.
                     tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
                     return;
@@ -1304,32 +1124,32 @@
             }
         }
 
-        debug!(
-            "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
-            trait_ref, candidate,
-        );
+        debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
         self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
     }
 
+    /// Matches a predicate against the bounds of its self type.
+    ///
+    /// Given an obligation like `<T as Foo>::Bar: Baz` where the self type is
+    /// a projection, look at the bounds of `T::Bar`, see if we can find a
+    /// `Baz` bound. We return indexes into the list returned by
+    /// `tcx.item_bounds` for any applicable bounds.
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-    ) -> bool {
+    ) -> smallvec::SmallVec<[usize; 2]> {
         let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
-        let (placeholder_trait_predicate, _) =
+        let placeholder_trait_predicate =
             self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             placeholder_trait_predicate={:?}",
-            placeholder_trait_predicate,
+            ?placeholder_trait_predicate,
+            "match_projection_obligation_against_definition_bounds"
         );
 
         let tcx = self.infcx.tcx;
-        let predicates = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
-            ty::Projection(ref data) => {
-                tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs)
-            }
-            ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs),
+        let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
+            ty::Projection(ref data) => (data.item_def_id, data.substs),
+            ty::Opaque(def_id, substs) => (def_id, substs),
             _ => {
                 span_bug!(
                     obligation.cause.span,
@@ -1339,48 +1159,83 @@
                 );
             }
         };
+        let bounds = tcx.item_bounds(def_id).subst(tcx, substs);
 
-        let matching_bound = predicates.iter().find_map(|bound| {
-            if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() {
-                let bound = ty::Binder::bind(pred.trait_ref);
-                if self.infcx.probe(|_| {
-                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref)
-                }) {
-                    return Some(bound);
+        // The bounds returned by `item_bounds` may contain duplicates after
+        // normalization, so try to deduplicate when possible to avoid
+        // unnecessary ambiguity.
+        let mut distinct_normalized_bounds = FxHashSet::default();
+
+        let matching_bounds = bounds
+            .iter()
+            .enumerate()
+            .filter_map(|(idx, bound)| {
+                let bound_predicate = bound.bound_atom();
+                if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() {
+                    let bound = bound_predicate.rebind(pred.trait_ref);
+                    if self.infcx.probe(|_| {
+                        match self.match_normalize_trait_ref(
+                            obligation,
+                            bound,
+                            placeholder_trait_predicate.trait_ref,
+                        ) {
+                            Ok(None) => true,
+                            Ok(Some(normalized_trait))
+                                if distinct_normalized_bounds.insert(normalized_trait) =>
+                            {
+                                true
+                            }
+                            _ => false,
+                        }
+                    }) {
+                        return Some(idx);
+                    }
                 }
-            }
-            None
-        });
+                None
+            })
+            .collect();
 
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             matching_bound={:?}",
-            matching_bound
-        );
-        match matching_bound {
-            None => false,
-            Some(bound) => {
-                // Repeat the successful match, if any, this time outside of a probe.
-                let result =
-                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref);
-
-                assert!(result);
-                true
-            }
-        }
+        debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
+        matching_bounds
     }
 
-    fn match_projection(
+    /// Equates the trait in `obligation` with trait bound. If the two traits
+    /// can be equated and the normalized trait bound doesn't contain inference
+    /// variables or placeholders, the normalized bound is returned.
+    fn match_normalize_trait_ref(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
         placeholder_trait_ref: ty::TraitRef<'tcx>,
-    ) -> bool {
+    ) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
         debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
+        if placeholder_trait_ref.def_id != trait_bound.def_id() {
+            // Avoid unnecessary normalization
+            return Err(());
+        }
+
+        let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
+            project::normalize_with_depth(
+                self,
+                obligation.param_env,
+                obligation.cause.clone(),
+                obligation.recursion_depth + 1,
+                &trait_bound,
+            )
+        });
         self.infcx
             .at(&obligation.cause, obligation.param_env)
             .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
-            .is_ok()
+            .map(|InferOk { obligations: _, value: () }| {
+                // This method is called within a probe, so we can't have
+                // inference variables and placeholders escape.
+                if !trait_bound.needs_infer() && !trait_bound.has_placeholders() {
+                    Some(trait_bound)
+                } else {
+                    None
+                }
+            })
+            .map_err(|_| ())
     }
 
     fn evaluate_where_clause<'o>(
@@ -1390,14 +1245,50 @@
     ) -> Result<EvaluationResult, OverflowError> {
         self.evaluation_probe(|this| {
             match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
-                Ok(obligations) => {
-                    this.evaluate_predicates_recursively(stack.list(), obligations.into_iter())
-                }
+                Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
                 Err(()) => Ok(EvaluatedToErr),
             }
         })
     }
 
+    pub(super) fn match_projection_projections(
+        &mut self,
+        obligation: &ProjectionTyObligation<'tcx>,
+        obligation_trait_ref: &ty::TraitRef<'tcx>,
+        data: &PolyProjectionPredicate<'tcx>,
+        potentially_unnormalized_candidates: bool,
+    ) -> bool {
+        let mut nested_obligations = Vec::new();
+        let projection_ty = if potentially_unnormalized_candidates {
+            ensure_sufficient_stack(|| {
+                project::normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    &data.map_bound_ref(|data| data.projection_ty),
+                    &mut nested_obligations,
+                )
+            })
+        } else {
+            data.map_bound_ref(|data| data.projection_ty)
+        };
+
+        // FIXME(generic_associated_types): Compare the whole projections
+        let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
+        let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
+        self.infcx
+            .at(&obligation.cause, obligation.param_env)
+            .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+            .map_or(false, |InferOk { obligations, value: () }| {
+                self.evaluate_predicates_recursively(
+                    TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
+                    nested_obligations.into_iter().chain(obligations),
+                )
+                .map_or(false, |res| res.may_apply())
+            })
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // WINNOW
     //
@@ -1432,18 +1323,27 @@
         //
         // This is a fix for #53123 and prevents winnowing from accidentally extending the
         // lifetime of a variable.
-        match other.candidate {
+        match (&other.candidate, &victim.candidate) {
+            (_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => {
+                bug!(
+                    "default implementations shouldn't be recorded \
+                    when there are other valid candidates"
+                );
+            }
+
             // (*)
-            BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => true,
-            ParamCandidate(ref cand) => match victim.candidate {
-                AutoImplCandidate(..) => {
-                    bug!(
-                        "default implementations shouldn't be recorded \
-                         when there are other valid candidates"
-                    );
-                }
-                // (*)
-                BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
+            (BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
+            (_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
+
+            (ParamCandidate(..), ParamCandidate(..)) => false,
+
+            // Global bounds from the where clause should be ignored
+            // here (see issue #50825). Otherwise, we have a where
+            // clause so don't go around looking for impls.
+            // Arbitrarily give param candidates priority
+            // over projection and object candidates.
+            (
+                ParamCandidate(ref cand),
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
@@ -1451,28 +1351,45 @@
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | BuiltinCandidate { .. }
-                | TraitAliasCandidate(..) => {
-                    // Global bounds from the where clause should be ignored
-                    // here (see issue #50825). Otherwise, we have a where
-                    // clause so don't go around looking for impls.
-                    !is_global(cand)
-                }
-                ObjectCandidate | ProjectionCandidate => {
-                    // Arbitrarily give param candidates priority
-                    // over projection and object candidates.
-                    !is_global(cand)
-                }
-                ParamCandidate(..) => false,
-            },
-            ObjectCandidate | ProjectionCandidate => match victim.candidate {
-                AutoImplCandidate(..) => {
-                    bug!(
-                        "default implementations shouldn't be recorded \
-                         when there are other valid candidates"
-                    );
-                }
-                // (*)
-                BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate => false,
+                | TraitAliasCandidate(..)
+                | ObjectCandidate(_)
+                | ProjectionCandidate(_),
+            ) => !is_global(cand),
+            (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
+                // Prefer these to a global where-clause bound
+                // (see issue #50825).
+                is_global(cand)
+            }
+            (
+                ImplCandidate(_)
+                | ClosureCandidate
+                | GeneratorCandidate
+                | FnPointerCandidate
+                | BuiltinObjectCandidate
+                | BuiltinUnsizeCandidate
+                | BuiltinCandidate { has_nested: true }
+                | TraitAliasCandidate(..),
+                ParamCandidate(ref cand),
+            ) => {
+                // Prefer these to a global where-clause bound
+                // (see issue #50825).
+                is_global(cand) && other.evaluation.must_apply_modulo_regions()
+            }
+
+            (ProjectionCandidate(i), ProjectionCandidate(j))
+            | (ObjectCandidate(i), ObjectCandidate(j)) => {
+                // Arbitrarily pick the lower numbered candidate for backwards
+                // compatibility reasons. Don't let this affect inference.
+                i < j && !needs_infer
+            }
+            (ObjectCandidate(_), ProjectionCandidate(_))
+            | (ProjectionCandidate(_), ObjectCandidate(_)) => {
+                bug!("Have both object and projection candidate")
+            }
+
+            // Arbitrarily give projection and object candidates priority.
+            (
+                ObjectCandidate(_) | ProjectionCandidate(_),
                 ImplCandidate(..)
                 | ClosureCandidate
                 | GeneratorCandidate
@@ -1480,98 +1397,100 @@
                 | BuiltinObjectCandidate
                 | BuiltinUnsizeCandidate
                 | BuiltinCandidate { .. }
-                | TraitAliasCandidate(..) => true,
-                ObjectCandidate | ProjectionCandidate => {
-                    // Arbitrarily give param candidates priority
-                    // over projection and object candidates.
-                    true
-                }
-                ParamCandidate(ref cand) => is_global(cand),
-            },
-            ImplCandidate(other_def) => {
+                | TraitAliasCandidate(..),
+            ) => true,
+
+            (
+                ImplCandidate(..)
+                | ClosureCandidate
+                | GeneratorCandidate
+                | FnPointerCandidate
+                | BuiltinObjectCandidate
+                | BuiltinUnsizeCandidate
+                | BuiltinCandidate { .. }
+                | TraitAliasCandidate(..),
+                ObjectCandidate(_) | ProjectionCandidate(_),
+            ) => false,
+
+            (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
                 // See if we can toss out `victim` based on specialization.
                 // This requires us to know *for sure* that the `other` impl applies
                 // i.e., `EvaluatedToOk`.
                 if other.evaluation.must_apply_modulo_regions() {
-                    match victim.candidate {
-                        ImplCandidate(victim_def) => {
-                            let tcx = self.tcx();
-                            if tcx.specializes((other_def, victim_def)) {
-                                return true;
-                            }
-                            return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
-                                Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
-                                    // Subtle: If the predicate we are evaluating has inference
-                                    // variables, do *not* allow discarding candidates due to
-                                    // marker trait impls.
-                                    //
-                                    // Without this restriction, we could end up accidentally
-                                    // constrainting inference variables based on an arbitrarily
-                                    // chosen trait impl.
-                                    //
-                                    // Imagine we have the following code:
-                                    //
-                                    // ```rust
-                                    // #[marker] trait MyTrait {}
-                                    // impl MyTrait for u8 {}
-                                    // impl MyTrait for bool {}
-                                    // ```
-                                    //
-                                    // And we are evaluating the predicate `<_#0t as MyTrait>`.
-                                    //
-                                    // During selection, we will end up with one candidate for each
-                                    // impl of `MyTrait`. If we were to discard one impl in favor
-                                    // of the other, we would be left with one candidate, causing
-                                    // us to "successfully" select the predicate, unifying
-                                    // _#0t with (for example) `u8`.
-                                    //
-                                    // However, we have no reason to believe that this unification
-                                    // is correct - we've essentially just picked an arbitrary
-                                    // *possibility* for _#0t, and required that this be the *only*
-                                    // possibility.
-                                    //
-                                    // Eventually, we will either:
-                                    // 1) Unify all inference variables in the predicate through
-                                    // some other means (e.g. type-checking of a function). We will
-                                    // then be in a position to drop marker trait candidates
-                                    // without constraining inference variables (since there are
-                                    // none left to constrin)
-                                    // 2) Be left with some unconstrained inference variables. We
-                                    // will then correctly report an inference error, since the
-                                    // existence of multiple marker trait impls tells us nothing
-                                    // about which one should actually apply.
-                                    !needs_infer
-                                }
-                                Some(_) => true,
-                                None => false,
-                            };
-                        }
-                        ParamCandidate(ref cand) => {
-                            // Prefer the impl to a global where clause candidate.
-                            return is_global(cand);
-                        }
-                        _ => (),
+                    let tcx = self.tcx();
+                    if tcx.specializes((other_def, victim_def)) {
+                        return true;
                     }
+                    return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+                        Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
+                            // Subtle: If the predicate we are evaluating has inference
+                            // variables, do *not* allow discarding candidates due to
+                            // marker trait impls.
+                            //
+                            // Without this restriction, we could end up accidentally
+                            // constrainting inference variables based on an arbitrarily
+                            // chosen trait impl.
+                            //
+                            // Imagine we have the following code:
+                            //
+                            // ```rust
+                            // #[marker] trait MyTrait {}
+                            // impl MyTrait for u8 {}
+                            // impl MyTrait for bool {}
+                            // ```
+                            //
+                            // And we are evaluating the predicate `<_#0t as MyTrait>`.
+                            //
+                            // During selection, we will end up with one candidate for each
+                            // impl of `MyTrait`. If we were to discard one impl in favor
+                            // of the other, we would be left with one candidate, causing
+                            // us to "successfully" select the predicate, unifying
+                            // _#0t with (for example) `u8`.
+                            //
+                            // However, we have no reason to believe that this unification
+                            // is correct - we've essentially just picked an arbitrary
+                            // *possibility* for _#0t, and required that this be the *only*
+                            // possibility.
+                            //
+                            // Eventually, we will either:
+                            // 1) Unify all inference variables in the predicate through
+                            // some other means (e.g. type-checking of a function). We will
+                            // then be in a position to drop marker trait candidates
+                            // without constraining inference variables (since there are
+                            // none left to constrin)
+                            // 2) Be left with some unconstrained inference variables. We
+                            // will then correctly report an inference error, since the
+                            // existence of multiple marker trait impls tells us nothing
+                            // about which one should actually apply.
+                            !needs_infer
+                        }
+                        Some(_) => true,
+                        None => false,
+                    };
+                } else {
+                    false
                 }
+            }
 
-                false
-            }
-            ClosureCandidate
-            | GeneratorCandidate
-            | FnPointerCandidate
-            | BuiltinObjectCandidate
-            | BuiltinUnsizeCandidate
-            | BuiltinCandidate { has_nested: true } => {
-                match victim.candidate {
-                    ParamCandidate(ref cand) => {
-                        // Prefer these to a global where-clause bound
-                        // (see issue #50825).
-                        is_global(cand) && other.evaluation.must_apply_modulo_regions()
-                    }
-                    _ => false,
-                }
-            }
-            _ => false,
+            // Everything else is ambiguous
+            (
+                ImplCandidate(_)
+                | ClosureCandidate
+                | GeneratorCandidate
+                | FnPointerCandidate
+                | BuiltinObjectCandidate
+                | BuiltinUnsizeCandidate
+                | BuiltinCandidate { has_nested: true }
+                | TraitAliasCandidate(..),
+                ImplCandidate(_)
+                | ClosureCandidate
+                | GeneratorCandidate
+                | FnPointerCandidate
+                | BuiltinObjectCandidate
+                | BuiltinUnsizeCandidate
+                | BuiltinCandidate { has_nested: true }
+                | TraitAliasCandidate(..),
+            ) => false,
         }
     }
 
@@ -1607,16 +1526,20 @@
 
             ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
 
-            ty::Tuple(tys) => {
-                Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect()))
-            }
+            ty::Tuple(tys) => Where(
+                obligation
+                    .predicate
+                    .rebind(tys.last().into_iter().map(|k| k.expect_ty()).collect()),
+            ),
 
             ty::Adt(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
-                Where(ty::Binder::bind(
-                    sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(),
-                ))
+                Where(
+                    obligation.predicate.rebind({
+                        sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
+                    }),
+                )
             }
 
             ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
@@ -1639,7 +1562,7 @@
 
         use self::BuiltinImplConditions::{Ambiguous, None, Where};
 
-        match self_ty.kind() {
+        match *self_ty.kind() {
             ty::Infer(ty::IntVar(_))
             | ty::Infer(ty::FloatVar(_))
             | ty::FnDef(..)
@@ -1668,17 +1591,23 @@
 
             ty::Array(element_ty, _) => {
                 // (*) binder moved here
-                Where(ty::Binder::bind(vec![element_ty]))
+                Where(obligation.predicate.rebind(vec![element_ty]))
             }
 
             ty::Tuple(tys) => {
                 // (*) binder moved here
-                Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect()))
+                Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect()))
             }
 
             ty::Closure(_, substs) => {
                 // (*) binder moved here
-                Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
+                let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
+                    // Not yet resolved.
+                    Ambiguous
+                } else {
+                    Where(obligation.predicate.rebind(substs.as_closure().upvar_tys().collect()))
+                }
             }
 
             ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
@@ -1747,11 +1676,15 @@
                 tys.iter().map(|k| k.expect_ty()).collect()
             }
 
-            ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(),
+            ty::Closure(_, ref substs) => {
+                let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+                vec![ty]
+            }
 
             ty::Generator(_, ref substs, _) => {
+                let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
                 let witness = substs.as_generator().witness();
-                substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
+                vec![ty].into_iter().chain(iter::once(witness)).collect()
             }
 
             ty::GeneratorWitness(types) => {
@@ -1804,7 +1737,7 @@
                 let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
 
                 self.infcx.commit_unconditionally(|_| {
-                    let (placeholder_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty);
+                    let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(&ty);
                     let Normalized { value: normalized_ty, mut obligations } =
                         ensure_sufficient_stack(|| {
                             project::normalize_with_depth(
@@ -1863,6 +1796,7 @@
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
+        debug!(?impl_def_id, ?obligation, "match_impl");
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
         // Before we create the substitutions and everything, first
@@ -1872,7 +1806,7 @@
             return Err(());
         }
 
-        let (placeholder_obligation, _) =
+        let placeholder_obligation =
             self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
         let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
 
@@ -1891,11 +1825,7 @@
                 )
             });
 
-        debug!(
-            "match_impl(impl_def_id={:?}, obligation={:?}, \
-             impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})",
-            impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref
-        );
+        debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref);
 
         let InferOk { obligations, .. } = self
             .infcx
@@ -1911,7 +1841,7 @@
             return Err(());
         }
 
-        debug!("match_impl: success impl_substs={:?}", impl_substs);
+        debug!(?impl_substs, "match_impl: success");
         Ok(Normalized { value: impl_substs, obligations: nested_obligations })
     }
 
@@ -1955,9 +1885,7 @@
 
     /// Normalize `where_clause_trait_ref` and try to match it against
     /// `obligation`. If successful, return any predicates that
-    /// result from the normalization. Normalization is necessary
-    /// because where-clauses are stored in the parameter environment
-    /// unnormalized.
+    /// result from the normalization.
     fn match_where_clause_trait_ref(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -1973,10 +1901,7 @@
         obligation: &TraitObligation<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
-        debug!(
-            "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
-            obligation, poly_trait_ref
-        );
+        debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref");
 
         self.infcx
             .at(&obligation.cause, obligation.param_env)
@@ -2023,10 +1948,10 @@
         obligation: &TraitObligation<'tcx>,
         substs: SubstsRef<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
-        debug!("closure_trait_ref_unnormalized(obligation={:?}, substs={:?})", obligation, substs);
+        debug!(?obligation, ?substs, "closure_trait_ref_unnormalized");
         let closure_sig = substs.as_closure().sig();
 
-        debug!("closure_trait_ref_unnormalized: closure_sig = {:?}", closure_sig);
+        debug!(?closure_sig);
 
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an unboxed closure type and hence is
@@ -2077,7 +2002,7 @@
         def_id: DefId,           // of impl or trait
         substs: SubstsRef<'tcx>, // for impl or trait
     ) -> Vec<PredicateObligation<'tcx>> {
-        debug!("impl_or_trait_obligations(def_id={:?})", def_id);
+        debug!(?def_id, "impl_or_trait_obligations");
         let tcx = self.tcx();
 
         // To allow for one-pass evaluation of the nested obligation,
@@ -2199,10 +2124,10 @@
             self.depth,
             reached_depth,
         );
-        debug!("update_reached_depth(reached_depth={})", reached_depth);
+        debug!(reached_depth, "update_reached_depth");
         let mut p = self;
         while reached_depth < p.depth {
-            debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref);
+            debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant");
             p.reached_depth.set(p.reached_depth.get().min(reached_depth));
             p = p.previous.head.unwrap();
         }
@@ -2329,10 +2254,10 @@
     /// `self.current_reached_depth()` and above.
     fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> {
         debug!(
-            "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}",
-            fresh_trait_ref,
+            ?fresh_trait_ref,
+            reached_depth = ?self.reached_depth.get(),
+            "get_provisional = {:#?}",
             self.map.borrow().get(&fresh_trait_ref),
-            self.reached_depth.get(),
         );
         Some(self.map.borrow().get(&fresh_trait_ref)?.result)
     }
@@ -2355,14 +2280,11 @@
         fresh_trait_ref: ty::PolyTraitRef<'tcx>,
         result: EvaluationResult,
     ) {
-        debug!(
-            "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})",
-            from_dfn, reached_depth, fresh_trait_ref, result,
-        );
+        debug!(?from_dfn, ?reached_depth, ?fresh_trait_ref, ?result, "insert_provisional");
         let r_d = self.reached_depth.get();
         self.reached_depth.set(r_d.min(reached_depth));
 
-        debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get());
+        debug!(reached_depth = self.reached_depth.get());
 
         self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result });
     }
@@ -2376,7 +2298,7 @@
     /// these provisional entries must either depend on it or some
     /// ancestor of it.
     fn on_failure(&self, dfn: usize) {
-        debug!("on_failure(dfn={:?})", dfn,);
+        debug!(?dfn, "on_failure");
         self.map.borrow_mut().retain(|key, eval| {
             if !eval.from_dfn >= dfn {
                 debug!("on_failure: removing {:?}", key);
@@ -2397,7 +2319,7 @@
         depth: usize,
         mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult),
     ) {
-        debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),);
+        debug!(?depth, reached_depth = ?self.reached_depth.get(), "on_completion");
 
         if self.reached_depth.get() < depth {
             debug!("on_completion: did not yet reach depth to complete");
@@ -2405,7 +2327,7 @@
         }
 
         for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() {
-            debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,);
+            debug!(?fresh_trait_ref, ?eval, "on_completion");
 
             op(fresh_trait_ref, eval.result);
         }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 909cd2a..496dff6 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -20,6 +20,7 @@
     infcx: &InferCtxt<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body_id: hir::HirId,
+    recursion_depth: usize,
     arg: GenericArg<'tcx>,
     span: Span,
 ) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
@@ -59,7 +60,8 @@
         GenericArgKind::Lifetime(..) => return Some(Vec::new()),
     };
 
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
+    let mut wf =
+        WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
     wf.compute(arg);
     debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
 
@@ -80,7 +82,8 @@
     span: Span,
     item: Option<&'tcx hir::Item<'tcx>>,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
+    let mut wf =
+        WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item };
     wf.compute_trait_ref(trait_ref, Elaborate::All);
     wf.normalize()
 }
@@ -92,7 +95,15 @@
     predicate: ty::Predicate<'tcx>,
     span: Span,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
-    let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
+    let mut wf = WfPredicates {
+        infcx,
+        param_env,
+        body_id,
+        span,
+        out: vec![],
+        recursion_depth: 0,
+        item: None,
+    };
 
     // It's ok to skip the binder here because wf code is prepared for it
     match predicate.skip_binders() {
@@ -142,6 +153,7 @@
     body_id: hir::HirId,
     span: Span,
     out: Vec<traits::PredicateObligation<'tcx>>,
+    recursion_depth: usize,
     item: Option<&'tcx hir::Item<'tcx>>,
 }
 
@@ -241,18 +253,27 @@
         traits::ObligationCause::new(self.span, self.body_id, code)
     }
 
-    fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
+    fn normalize(mut self) -> Vec<traits::PredicateObligation<'tcx>> {
         let cause = self.cause(traits::MiscObligation);
         let infcx = &mut self.infcx;
         let param_env = self.param_env;
         let mut obligations = Vec::with_capacity(self.out.len());
-        for pred in &self.out {
-            assert!(!pred.has_escaping_bound_vars());
+        for mut obligation in self.out {
+            assert!(!obligation.has_escaping_bound_vars());
             let mut selcx = traits::SelectionContext::new(infcx);
-            let i = obligations.len();
-            let value =
-                traits::normalize_to(&mut selcx, param_env, cause.clone(), pred, &mut obligations);
-            obligations.insert(i, value);
+            // Don't normalize the whole obligation, the param env is either
+            // already normalized, or we're currently normalizing the
+            // param_env. Either way we should only normalize the predicate.
+            let normalized_predicate = traits::project::normalize_with_depth_to(
+                &mut selcx,
+                param_env,
+                cause.clone(),
+                self.recursion_depth,
+                &obligation.predicate,
+                &mut obligations,
+            );
+            obligation.predicate = normalized_predicate;
+            obligations.push(obligation);
         }
         obligations
     }
@@ -265,6 +286,7 @@
         debug!("compute_trait_ref obligations {:?}", obligations);
         let cause = self.cause(traits::MiscObligation);
         let param_env = self.param_env;
+        let depth = self.recursion_depth;
 
         let item = self.item;
 
@@ -286,7 +308,7 @@
                 &obligation.predicate,
                 tcx.associated_items(trait_ref.def_id).in_definition_order(),
             );
-            traits::Obligation::new(cause, param_env, obligation.predicate)
+            traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
         };
 
         if let Elaborate::All = elaborate {
@@ -315,8 +337,9 @@
                             new_cause.make_mut().span = self_ty.span;
                         }
                     }
-                    traits::Obligation::new(
+                    traits::Obligation::with_depth(
                         new_cause,
+                        depth,
                         param_env,
                         ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
                     )
@@ -327,17 +350,51 @@
     /// Pushes the obligations required for `trait_ref::Item` to be WF
     /// into `self.out`.
     fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
-        // A projection is well-formed if (a) the trait ref itself is
-        // WF and (b) the trait-ref holds.  (It may also be
-        // normalizable and be WF that way.)
-        let trait_ref = data.trait_ref(self.infcx.tcx);
-        self.compute_trait_ref(&trait_ref, Elaborate::None);
+        // A projection is well-formed if
+        //
+        // (a) its predicates hold (*)
+        // (b) its substs are wf
+        //
+        // (*) The predicates of an associated type include the predicates of
+        //     the trait that it's contained in. For example, given
+        //
+        // trait A<T>: Clone {
+        //     type X where T: Copy;
+        // }
+        //
+        // The predicates of `<() as A<i32>>::X` are:
+        // [
+        //     `(): Sized`
+        //     `(): Clone`
+        //     `(): A<i32>`
+        //     `i32: Sized`
+        //     `i32: Clone`
+        //     `i32: Copy`
+        // ]
+        let obligations = self.nominal_obligations(data.item_def_id, data.substs);
+        self.out.extend(obligations);
 
-        if !data.has_escaping_bound_vars() {
-            let predicate = trait_ref.without_const().to_predicate(self.infcx.tcx);
-            let cause = self.cause(traits::ProjectionWf(data));
-            self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
-        }
+        let tcx = self.tcx();
+        let cause = self.cause(traits::MiscObligation);
+        let param_env = self.param_env;
+        let depth = self.recursion_depth;
+
+        self.out.extend(
+            data.substs
+                .iter()
+                .filter(|arg| {
+                    matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+                })
+                .filter(|arg| !arg.has_escaping_bound_vars())
+                .map(|arg| {
+                    traits::Obligation::with_depth(
+                        cause.clone(),
+                        depth,
+                        param_env,
+                        ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
+                    )
+                }),
+        );
     }
 
     fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
@@ -347,8 +404,9 @@
                 def_id: self.infcx.tcx.require_lang_item(LangItem::Sized, None),
                 substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
             };
-            self.out.push(traits::Obligation::new(
+            self.out.push(traits::Obligation::with_depth(
                 cause,
+                self.recursion_depth,
                 self.param_env,
                 trait_ref.without_const().to_predicate(self.infcx.tcx),
             ));
@@ -359,6 +417,7 @@
     fn compute(&mut self, arg: GenericArg<'tcx>) {
         let mut walker = arg.walk();
         let param_env = self.param_env;
+        let depth = self.recursion_depth;
         while let Some(arg) = walker.next() {
             let ty = match arg.unpack() {
                 GenericArgKind::Type(ty) => ty,
@@ -378,8 +437,9 @@
                             let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs)
                                 .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
-                            self.out.push(traits::Obligation::new(
+                            self.out.push(traits::Obligation::with_depth(
                                 cause,
+                                self.recursion_depth,
                                 self.param_env,
                                 predicate,
                             ));
@@ -394,8 +454,9 @@
                                     val: ty::ConstKind::Infer(resolved),
                                     ..*constant
                                 });
-                                self.out.push(traits::Obligation::new(
+                                self.out.push(traits::Obligation::with_depth(
                                     cause,
+                                    self.recursion_depth,
                                     self.param_env,
                                     ty::PredicateAtom::WellFormed(resolved_constant.into())
                                         .to_predicate(self.tcx()),
@@ -480,8 +541,9 @@
                     // WfReference
                     if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
                         let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
-                        self.out.push(traits::Obligation::new(
+                        self.out.push(traits::Obligation::with_depth(
                             cause,
+                            depth,
                             param_env,
                             ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(rty, r))
                                 .to_predicate(self.tcx()),
@@ -530,10 +592,8 @@
                     // anyway, except via auto trait matching (which
                     // only inspects the upvar types).
                     walker.skip_current_subtree(); // subtree handled below
-                    for upvar_ty in substs.as_closure().upvar_tys() {
-                        // FIXME(eddyb) add the type to `walker` instead of recursing.
-                        self.compute(upvar_ty.into());
-                    }
+                    // FIXME(eddyb) add the type to `walker` instead of recursing.
+                    self.compute(substs.as_closure().tupled_upvars_ty().into());
                 }
 
                 ty::FnPtr(_) => {
@@ -571,8 +631,9 @@
                         let component_traits = data.auto_traits().chain(data.principal_def_id());
                         let tcx = self.tcx();
                         self.out.extend(component_traits.map(|did| {
-                            traits::Obligation::new(
+                            traits::Obligation::with_depth(
                                 cause.clone(),
+                                depth,
                                 param_env,
                                 ty::PredicateAtom::ObjectSafe(did).to_predicate(tcx),
                             )
@@ -597,8 +658,9 @@
                     if let ty::Infer(ty::TyVar(_)) = ty.kind() {
                         // Not yet resolved, but we've made progress.
                         let cause = self.cause(traits::MiscObligation);
-                        self.out.push(traits::Obligation::new(
+                        self.out.push(traits::Obligation::with_depth(
                             cause,
+                            self.recursion_depth,
                             param_env,
                             ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()),
                         ));
@@ -635,7 +697,7 @@
             .zip(origins.into_iter().rev())
             .map(|((pred, span), origin_def_id)| {
                 let cause = self.cause(traits::BindingObligation(origin_def_id, span));
-                traits::Obligation::new(cause, self.param_env, pred)
+                traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)
             })
             .filter(|pred| !pred.has_escaping_bound_vars())
             .collect()
@@ -688,8 +750,9 @@
                 let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
                 let outlives =
                     ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
-                self.out.push(traits::Obligation::new(
+                self.out.push(traits::Obligation::with_depth(
                     cause,
+                    self.recursion_depth,
                     self.param_env,
                     outlives.to_predicate(self.infcx.tcx),
                 ));
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index 6d49571..a54fe08 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -12,9 +12,9 @@
 rustc_index = { path = "../rustc_index" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.29.0"
-chalk-solve = "0.29.0"
-chalk-engine = "0.29.0"
+chalk-ir = "0.32.0"
+chalk-solve = "0.32.0"
+chalk-engine = "0.32.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 828ee6d..3368c5b 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -22,7 +22,6 @@
 
 pub struct RustIrDatabase<'tcx> {
     pub(crate) interner: RustInterner<'tcx>,
-    pub(crate) restatic_placeholder: ty::Region<'tcx>,
     pub(crate) reempty_placeholder: ty::Region<'tcx>,
 }
 
@@ -39,17 +38,27 @@
         bound_vars: SubstsRef<'tcx>,
     ) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
         let predicates = self.interner.tcx.predicates_of(def_id).predicates;
-        let mut regions_substitutor = lowering::RegionsSubstitutor::new(
-            self.interner.tcx,
-            self.restatic_placeholder,
-            self.reempty_placeholder,
-        );
+        let mut regions_substitutor =
+            lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
         predicates
             .iter()
             .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
             .map(|wc| wc.fold_with(&mut regions_substitutor))
             .filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect()
     }
+
+    fn bounds_for<T>(&self, def_id: DefId, bound_vars: SubstsRef<'tcx>) -> Vec<T>
+    where
+        ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>,
+    {
+        self.interner
+            .tcx
+            .explicit_item_bounds(def_id)
+            .iter()
+            .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
+            .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, &self.interner))
+            .collect()
+    }
 }
 
 impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'tcx> {
@@ -73,10 +82,9 @@
         }
         let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
         let binders = binders_for(&self.interner, bound_vars);
-        // FIXME(chalk): this really isn't right I don't think. The functions
-        // for GATs are a bit hard to figure out. Are these supposed to be where
-        // clauses or bounds?
+
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
+        let bounds = self.bounds_for(def_id, bound_vars);
 
         Arc::new(chalk_solve::rust_ir::AssociatedTyDatum {
             trait_id: chalk_ir::TraitId(trait_def_id),
@@ -84,7 +92,7 @@
             name: (),
             binders: chalk_ir::Binders::new(
                 binders,
-                chalk_solve::rust_ir::AssociatedTyDatumBound { bounds: vec![], where_clauses },
+                chalk_solve::rust_ir::AssociatedTyDatumBound { bounds, where_clauses },
             ),
         })
     }
@@ -262,11 +270,8 @@
 
         let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
         let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
-        let mut regions_substitutor = lowering::RegionsSubstitutor::new(
-            self.interner.tcx,
-            self.restatic_placeholder,
-            self.reempty_placeholder,
-        );
+        let mut regions_substitutor =
+            lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
         let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
@@ -304,11 +309,8 @@
 
             let self_ty = trait_ref.self_ty();
             let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
-            let mut regions_substitutor = lowering::RegionsSubstitutor::new(
-                self.interner.tcx,
-                self.restatic_placeholder,
-                self.reempty_placeholder,
-            );
+            let mut regions_substitutor =
+                lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
             let self_ty = self_ty.fold_with(&mut regions_substitutor);
             let lowered_ty = self_ty.lower_into(&self.interner);
 
@@ -442,11 +444,13 @@
         let bound_vars = bound_vars_for_item(self.interner.tcx, opaque_ty_id.0);
         let binders = binders_for(&self.interner, bound_vars);
         let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars);
+        let bounds = self.bounds_for(opaque_ty_id.0, bound_vars);
 
         let value = chalk_solve::rust_ir::OpaqueTyDatumBound {
-            bounds: chalk_ir::Binders::new(binders.clone(), vec![]),
+            bounds: chalk_ir::Binders::new(binders.clone(), bounds),
             where_clauses: chalk_ir::Binders::new(binders, where_clauses),
         };
+
         Arc::new(chalk_solve::rust_ir::OpaqueTyDatum {
             opaque_ty_id,
             bound: chalk_ir::Binders::empty(&self.interner, value),
@@ -576,6 +580,20 @@
         let substitution = &substs.as_slice(&self.interner)[0..substs.len(&self.interner) - 3];
         chalk_ir::Substitution::from_iter(&self.interner, substitution)
     }
+
+    fn generator_datum(
+        &self,
+        _generator_id: chalk_ir::GeneratorId<RustInterner<'tcx>>,
+    ) -> Arc<chalk_solve::rust_ir::GeneratorDatum<RustInterner<'tcx>>> {
+        unimplemented!()
+    }
+
+    fn generator_witness_datum(
+        &self,
+        _generator_id: chalk_ir::GeneratorId<RustInterner<'tcx>>,
+    ) -> Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<RustInterner<'tcx>>> {
+        unimplemented!()
+    }
 }
 
 /// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 1e1841a..5ca0fc0 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -81,8 +81,11 @@
         interner: &RustInterner<'tcx>,
     ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
         let clauses = self.environment.into_iter().map(|predicate| {
-            let (predicate, binders, _named_regions) =
-                collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx));
+            let (predicate, binders, _named_regions) = collect_bound_vars(
+                interner,
+                interner.tcx,
+                &predicate.bound_atom_with_opt_escaping(interner.tcx),
+            );
             let consequence = match predicate {
                 ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
                     chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner)))
@@ -133,8 +136,11 @@
 
 impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predicate<'tcx> {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
-        let (predicate, binders, _named_regions) =
-            collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx));
+        let (predicate, binders, _named_regions) = collect_bound_vars(
+            interner,
+            interner.tcx,
+            &self.bound_atom_with_opt_escaping(interner.tcx),
+        );
 
         let value = match predicate {
             ty::PredicateAtom::Trait(predicate, _) => {
@@ -427,13 +433,20 @@
                         chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64),
                     },
                 },
-                chalk_ir::TypeName::Array => unimplemented!(),
+                chalk_ir::TypeName::Array => {
+                    let substs = application_ty.substitution.as_slice(interner);
+                    let ty = substs[0].assert_ty_ref(interner).lower_into(interner);
+                    let c = substs[1].assert_const_ref(interner).lower_into(interner);
+                    ty::Array(ty, interner.tcx.mk_const(c))
+                }
                 chalk_ir::TypeName::FnDef(id) => {
                     ty::FnDef(id.0, application_ty.substitution.lower_into(interner))
                 }
                 chalk_ir::TypeName::Closure(closure) => {
                     ty::Closure(closure.0, application_ty.substitution.lower_into(interner))
                 }
+                chalk_ir::TypeName::Generator(_) => unimplemented!(),
+                chalk_ir::TypeName::GeneratorWitness(_) => unimplemented!(),
                 chalk_ir::TypeName::Never => ty::Never,
                 chalk_ir::TypeName::Tuple(_size) => {
                     ty::Tuple(application_ty.substitution.lower_into(interner))
@@ -483,7 +496,15 @@
                 universe: ty::UniverseIndex::from_usize(placeholder.ui.counter),
                 name: ty::BoundVar::from_usize(placeholder.idx),
             }),
-            TyData::Alias(_alias_ty) => unimplemented!(),
+            chalk_ir::TyData::Alias(alias_ty) => match alias_ty {
+                chalk_ir::AliasTy::Projection(projection) => ty::Projection(ty::ProjectionTy {
+                    item_def_id: projection.associated_ty_id.0,
+                    substs: projection.substitution.lower_into(interner),
+                }),
+                chalk_ir::AliasTy::Opaque(opaque) => {
+                    ty::Opaque(opaque.opaque_ty_id.0, opaque.substitution.lower_into(interner))
+                }
+            },
             TyData::Function(_quantified_ty) => unimplemented!(),
             TyData::BoundVar(_bound) => ty::Bound(
                 ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize),
@@ -519,8 +540,7 @@
                 ty::BrEnv => unimplemented!(),
             },
             ReFree(_) => unimplemented!(),
-            // FIXME(chalk): need to handle ReStatic
-            ReStatic => unimplemented!(),
+            ReStatic => chalk_ir::LifetimeData::Static.intern(interner),
             ReVar(_) => unimplemented!(),
             RePlaceholder(placeholder_region) => {
                 chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex {
@@ -550,6 +570,7 @@
                     name: ty::BoundRegion::BrAnon(p.idx as u32),
                 })
             }
+            chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic,
             chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(),
         };
         interner.tcx.mk_region(kind)
@@ -638,8 +659,11 @@
         self,
         interner: &RustInterner<'tcx>,
     ) -> Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
-        let (predicate, binders, _named_regions) =
-            collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx));
+        let (predicate, binders, _named_regions) = collect_bound_vars(
+            interner,
+            interner.tcx,
+            &self.bound_atom_with_opt_escaping(interner.tcx),
+        );
         let value = match predicate {
             ty::PredicateAtom::Trait(predicate, _) => {
                 Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)))
@@ -701,7 +725,16 @@
                     }),
                 )
             }
-            ty::ExistentialPredicate::Projection(_predicate) => unimplemented!(),
+            ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new(
+                chalk_ir::VariableKinds::empty(interner),
+                chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq {
+                    alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
+                        associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id),
+                        substitution: predicate.substs.lower_into(interner),
+                    }),
+                    ty: predicate.ty.lower_into(interner),
+                }),
+            ),
             ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
                 chalk_ir::VariableKinds::empty(interner),
                 chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
@@ -728,6 +761,82 @@
     }
 }
 
+// We lower into an Option here since there are some predicates which Chalk
+// doesn't have a representation for yet (as an `InlineBound`). The `Option` will
+// eventually be removed.
+impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>>>
+    for ty::Predicate<'tcx>
+{
+    fn lower_into(
+        self,
+        interner: &RustInterner<'tcx>,
+    ) -> Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>> {
+        let (predicate, binders, _named_regions) = collect_bound_vars(
+            interner,
+            interner.tcx,
+            &self.bound_atom_with_opt_escaping(interner.tcx),
+        );
+        match predicate {
+            ty::PredicateAtom::Trait(predicate, _) => Some(chalk_ir::Binders::new(
+                binders,
+                chalk_solve::rust_ir::InlineBound::TraitBound(
+                    predicate.trait_ref.lower_into(interner),
+                ),
+            )),
+            ty::PredicateAtom::Projection(predicate) => Some(chalk_ir::Binders::new(
+                binders,
+                chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)),
+            )),
+            ty::PredicateAtom::TypeOutlives(_predicate) => None,
+            ty::PredicateAtom::WellFormed(_ty) => None,
+
+            ty::PredicateAtom::RegionOutlives(..)
+            | ty::PredicateAtom::ObjectSafe(..)
+            | ty::PredicateAtom::ClosureKind(..)
+            | ty::PredicateAtom::Subtype(..)
+            | ty::PredicateAtom::ConstEvaluatable(..)
+            | ty::PredicateAtom::ConstEquate(..)
+            | ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+                bug!("unexpected predicate {}", &self)
+            }
+        }
+    }
+}
+
+impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>>>
+    for ty::TraitRef<'tcx>
+{
+    fn lower_into(
+        self,
+        interner: &RustInterner<'tcx>,
+    ) -> chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>> {
+        chalk_solve::rust_ir::TraitBound {
+            trait_id: chalk_ir::TraitId(self.def_id),
+            args_no_self: self.substs[1..].iter().map(|arg| arg.lower_into(interner)).collect(),
+        }
+    }
+}
+
+impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
+    for ty::ProjectionPredicate<'tcx>
+{
+    fn lower_into(
+        self,
+        interner: &RustInterner<'tcx>,
+    ) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
+        let trait_ref = self.projection_ty.trait_ref(interner.tcx);
+        chalk_solve::rust_ir::AliasEqBound {
+            trait_bound: trait_ref.lower_into(interner),
+            associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
+            parameters: self.projection_ty.substs[trait_ref.substs.len()..]
+                .iter()
+                .map(|arg| arg.lower_into(interner))
+                .collect(),
+            value: self.ty.lower_into(interner),
+        }
+    }
+}
+
 /// To collect bound vars, we have to do two passes. In the first pass, we
 /// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then
 /// replace `BrNamed` into `BrAnon`. The two separate passes are important,
@@ -1035,17 +1144,12 @@
 /// Used to substitute specific `Regions`s with placeholders.
 crate struct RegionsSubstitutor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    restatic_placeholder: ty::Region<'tcx>,
     reempty_placeholder: ty::Region<'tcx>,
 }
 
 impl<'tcx> RegionsSubstitutor<'tcx> {
-    crate fn new(
-        tcx: TyCtxt<'tcx>,
-        restatic_placeholder: ty::Region<'tcx>,
-        reempty_placeholder: ty::Region<'tcx>,
-    ) -> Self {
-        RegionsSubstitutor { tcx, restatic_placeholder, reempty_placeholder }
+    crate fn new(tcx: TyCtxt<'tcx>, reempty_placeholder: ty::Region<'tcx>) -> Self {
+        RegionsSubstitutor { tcx, reempty_placeholder }
     }
 }
 
@@ -1056,7 +1160,6 @@
 
     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
         match r {
-            ty::ReStatic => self.restatic_placeholder,
             ty::ReEmpty(ui) => {
                 assert_eq!(ui.as_usize(), 0);
                 self.reempty_placeholder
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index 63c5b88..f174a92 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -42,10 +42,6 @@
     let mut placeholders_collector = PlaceholdersCollector::new();
     obligation.visit_with(&mut placeholders_collector);
 
-    let restatic_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
-        universe: ty::UniverseIndex::ROOT,
-        name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder),
-    }));
     let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
         universe: ty::UniverseIndex::ROOT,
         name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder + 1),
@@ -57,8 +53,7 @@
     // FIXME(chalk): we really should be substituting these back in the solution
     let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
 
-    let mut regions_substitutor =
-        RegionsSubstitutor::new(tcx, restatic_placeholder, reempty_placeholder);
+    let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
     let obligation = obligation.fold_with(&mut regions_substitutor);
 
     let max_universe = obligation.max_universe.index();
@@ -101,7 +96,7 @@
 
     use chalk_solve::Solver;
     let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
-    let db = ChalkRustIrDatabase { interner, restatic_placeholder, reempty_placeholder };
+    let db = ChalkRustIrDatabase { interner, reempty_placeholder };
     let solution = chalk_solve::logging::with_tracing_logs(|| solver.solve(&db, &lowered_goal));
 
     // Ideally, the code to convert *back* to rustc types would live close to
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 3ee391d..6cffa6d 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -210,12 +210,25 @@
             Ok::<_, NoSolution>(())
         })?,
 
-        ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
-            for ty in substs.as_closure().upvar_tys() {
-                dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
+        ty::Closure(_, substs) => {
+            if !substs.as_closure().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+
+                tcx.sess.delay_span_bug(
+                    span,
+                    &format!("upvar_tys for closure not found. Expected capture information for closure {}", ty,),
+                );
+                return Err(NoSolution);
             }
-            Ok::<_, NoSolution>(())
-        })?,
+
+            rustc_data_structures::stack::ensure_sufficient_stack(|| {
+                for ty in substs.as_closure().upvar_tys() {
+                    dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
+                }
+                Ok::<_, NoSolution>(())
+            })?
+        }
 
         ty::Generator(_, substs, _movability) => {
             // rust-lang/rust#49918: types can be constructed, stored
@@ -241,6 +254,16 @@
             // derived from lifetimes attached to the upvars and resume
             // argument, and we *do* incorporate those here.
 
+            if !substs.as_generator().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+                tcx.sess.delay_span_bug(
+                    span,
+                    &format!("upvar_tys for generator not found. Expected capture information for generator {}", ty,),
+                );
+                return Err(NoSolution);
+            }
+
             constraints.outlives.extend(
                 substs
                     .as_generator()
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 79308b0..bc5c07f 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -61,8 +61,8 @@
         // than the ultimate set. (Note: normally there won't be
         // unresolved inference variables here anyway, but there might be
         // during typeck under some circumstances.)
-        let obligations =
-            wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, arg, DUMMY_SP).unwrap_or(vec![]);
+        let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
+            .unwrap_or(vec![]);
 
         // N.B., all of these predicates *ought* to be easily proven
         // true. In fact, their correctness is (mostly) implied by
diff --git a/compiler/rustc_ty/src/ty.rs b/compiler/rustc_ty/src/ty.rs
index c4b6b64..2562140 100644
--- a/compiler/rustc_ty/src/ty.rs
+++ b/compiler/rustc_ty/src/ty.rs
@@ -1,11 +1,9 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_infer::traits::util;
 use rustc_middle::hir::map as hir_map;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{
     self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
 };
@@ -82,7 +80,6 @@
 fn associated_item_from_trait_item_ref(
     tcx: TyCtxt<'_>,
     parent_def_id: LocalDefId,
-    parent_vis: &hir::Visibility<'_>,
     trait_item_ref: &hir::TraitItemRef,
 ) -> ty::AssocItem {
     let def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
@@ -95,8 +92,7 @@
     ty::AssocItem {
         ident: trait_item_ref.ident,
         kind,
-        // Visibility of trait items is inherited from their traits.
-        vis: ty::Visibility::from_hir(parent_vis, trait_item_ref.id.hir_id, tcx),
+        vis: tcx.visibility(def_id),
         defaultness: trait_item_ref.defaultness,
         def_id: def_id.to_def_id(),
         container: ty::TraitContainer(parent_def_id.to_def_id()),
@@ -119,8 +115,7 @@
     ty::AssocItem {
         ident: impl_item_ref.ident,
         kind,
-        // Visibility of trait impl items doesn't matter.
-        vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.hir_id, tcx),
+        vis: tcx.visibility(def_id),
         defaultness: impl_item_ref.defaultness,
         def_id: def_id.to_def_id(),
         container: ty::ImplContainer(parent_def_id.to_def_id()),
@@ -145,12 +140,8 @@
 
         hir::ItemKind::Trait(.., ref trait_item_refs) => {
             if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.hir_id == id) {
-                let assoc_item = associated_item_from_trait_item_ref(
-                    tcx,
-                    parent_def_id,
-                    &parent_item.vis,
-                    trait_item_ref,
-                );
+                let assoc_item =
+                    associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
                 return assoc_item;
             }
@@ -492,133 +483,6 @@
     fn_like.asyncness()
 }
 
-/// For associated types we allow bounds written on the associated type
-/// (`type X: Trait`) to be used as candidates. We also allow the same bounds
-/// when desugared as bounds on the trait `where Self::X: Trait`.
-///
-/// Note that this filtering is done with the items identity substs to
-/// simplify checking that these bounds are met in impls. This means that
-/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
-/// `hr-associated-type-bound-1.rs`.
-fn associated_type_projection_predicates(
-    tcx: TyCtxt<'_>,
-    assoc_item_def_id: DefId,
-) -> &'_ ty::List<ty::Predicate<'_>> {
-    let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id);
-    // We include predicates from the trait as well to handle
-    // `where Self::X: Trait`.
-    let item_bounds = generic_trait_bounds.instantiate_identity(tcx);
-    let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter());
-
-    let assoc_item_ty = ty::ProjectionTy {
-        item_def_id: assoc_item_def_id,
-        substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
-    };
-
-    let predicates = item_predicates.filter_map(|obligation| {
-        let pred = obligation.predicate;
-        match pred.skip_binders() {
-            ty::PredicateAtom::Trait(tr, _) => {
-                if let ty::Projection(p) = *tr.self_ty().kind() {
-                    if p == assoc_item_ty {
-                        return Some(pred);
-                    }
-                }
-            }
-            ty::PredicateAtom::Projection(proj) => {
-                if let ty::Projection(p) = *proj.projection_ty.self_ty().kind() {
-                    if p == assoc_item_ty {
-                        return Some(pred);
-                    }
-                }
-            }
-            ty::PredicateAtom::TypeOutlives(outlives) => {
-                if let ty::Projection(p) = *outlives.0.kind() {
-                    if p == assoc_item_ty {
-                        return Some(pred);
-                    }
-                }
-            }
-            _ => {}
-        }
-        None
-    });
-
-    let result = tcx.mk_predicates(predicates);
-    debug!(
-        "associated_type_projection_predicates({}) = {:?}",
-        tcx.def_path_str(assoc_item_def_id),
-        result
-    );
-    result
-}
-
-/// Opaque types don't have the same issues as associated types: the only
-/// predicates on an opaque type (excluding those it inherits from its parent
-/// item) should be of the form we're expecting.
-fn opaque_type_projection_predicates(
-    tcx: TyCtxt<'_>,
-    def_id: DefId,
-) -> &'_ ty::List<ty::Predicate<'_>> {
-    let substs = InternalSubsts::identity_for_item(tcx, def_id);
-
-    let bounds = tcx.predicates_of(def_id);
-    let predicates =
-        util::elaborate_predicates(tcx, bounds.predicates.iter().map(|&(pred, _)| pred));
-
-    let filtered_predicates = predicates.filter_map(|obligation| {
-        let pred = obligation.predicate;
-        match pred.skip_binders() {
-            ty::PredicateAtom::Trait(tr, _) => {
-                if let ty::Opaque(opaque_def_id, opaque_substs) = *tr.self_ty().kind() {
-                    if opaque_def_id == def_id && opaque_substs == substs {
-                        return Some(pred);
-                    }
-                }
-            }
-            ty::PredicateAtom::Projection(proj) => {
-                if let ty::Opaque(opaque_def_id, opaque_substs) =
-                    *proj.projection_ty.self_ty().kind()
-                {
-                    if opaque_def_id == def_id && opaque_substs == substs {
-                        return Some(pred);
-                    }
-                }
-            }
-            ty::PredicateAtom::TypeOutlives(outlives) => {
-                if let ty::Opaque(opaque_def_id, opaque_substs) = *outlives.0.kind() {
-                    if opaque_def_id == def_id && opaque_substs == substs {
-                        return Some(pred);
-                    }
-                } else {
-                    // These can come from elaborating other predicates
-                    return None;
-                }
-            }
-            // These can come from elaborating other predicates
-            ty::PredicateAtom::RegionOutlives(_) => return None,
-            _ => {}
-        }
-        tcx.sess.delay_span_bug(
-            obligation.cause.span(tcx),
-            &format!("unexpected predicate {:?} on opaque type", pred),
-        );
-        None
-    });
-
-    let result = tcx.mk_predicates(filtered_predicates);
-    debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result);
-    result
-}
-
-fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
-    match tcx.def_kind(def_id) {
-        DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id),
-        DefKind::OpaqueTy => opaque_type_projection_predicates(tcx, def_id),
-        k => bug!("projection_predicates called on {}", k.descr(def_id)),
-    }
-}
-
 pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         asyncness,
@@ -636,7 +500,6 @@
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
-        projection_predicates,
         ..*providers
     };
 }
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index b54de1d..b867798 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -562,7 +562,7 @@
                 .args
                 .iter()
                 .filter_map(|arg| match arg {
-                    GenericArg::Type(_) => Some(arg.span()),
+                    GenericArg::Type(_) | GenericArg::Const(_) => Some(arg.span()),
                     _ => None,
                 })
                 .collect::<Vec<_>>();
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 46b8b2e..07e523a 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -35,8 +35,8 @@
 use rustc_trait_selection::traits::wf::object_region_bounds;
 
 use smallvec::SmallVec;
+use std::array;
 use std::collections::BTreeSet;
-use std::iter;
 use std::slice;
 
 #[derive(Debug)]
@@ -1095,9 +1095,10 @@
                     obligation.predicate
                 );
 
-                match obligation.predicate.skip_binders() {
+                let bound_predicate = obligation.predicate.bound_atom();
+                match bound_predicate.skip_binder() {
                     ty::PredicateAtom::Trait(pred, _) => {
-                        let pred = ty::Binder::bind(pred);
+                        let pred = bound_predicate.rebind(pred);
                         associated_types.entry(span).or_default().extend(
                             tcx.associated_items(pred.def_id())
                                 .in_definition_order()
@@ -1106,7 +1107,7 @@
                         );
                     }
                     ty::PredicateAtom::Projection(pred) => {
-                        let pred = ty::Binder::bind(pred);
+                        let pred = bound_predicate.rebind(pred);
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
                         let references_self =
@@ -1346,7 +1347,7 @@
             debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
 
             let is_equality = is_equality();
-            let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates);
+            let bounds = array::IntoIter::new([bound, bound2]).chain(matching_candidates);
             let mut err = if is_equality.is_some() {
                 // More specific Error Index entry.
                 struct_span_err!(
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 63295f5..6837074 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -71,10 +71,6 @@
                 self.region_bounds
                     .iter()
                     .map(|&(region_bound, span)| {
-                        // Account for the binder being introduced below; no need to shift `param_ty`
-                        // because, at present at least, it either only refers to early-bound regions,
-                        // or it's a generic associated type that deliberately has escaping bound vars.
-                        let region_bound = ty::fold::shift_region(tcx, region_bound, 1);
                         let outlives = ty::OutlivesPredicate(param_ty, region_bound);
                         (ty::Binder::bind(outlives).to_predicate(tcx), span)
                     })
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 7cb23dc..398e013 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -201,6 +201,7 @@
                         expr.span,
                         ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
                             arm_span,
+                            scrut_span: scrut.span,
                             semi_span,
                             source: match_src,
                             prior_arms: other_arms.clone(),
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 740783a..a38fb96 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -285,10 +285,8 @@
         arg_exprs: &'tcx [hir::Expr<'tcx>],
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let (fn_sig, def_span) = match *callee_ty.kind() {
-            ty::FnDef(def_id, _) => {
-                (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id))
-            }
+        let (fn_sig, def_id) = match *callee_ty.kind() {
+            ty::FnDef(def_id, _) => (callee_ty.fn_sig(self.tcx), Some(def_id)),
             ty::FnPtr(sig) => (sig, None),
             ref t => {
                 let mut unit_variant = None;
@@ -427,7 +425,7 @@
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::DontTupleArguments,
-            def_span,
+            def_id,
         );
 
         fn_sig.output()
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 2daa035..3d8653b 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1,15 +1,16 @@
 use super::coercion::CoerceMany;
+use super::compare_method::check_type_bounds;
 use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
 use super::*;
 
 use rustc_attr as attr;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemKind, Node};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::RegionVariableOrigin;
+use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
@@ -18,6 +19,8 @@
 use rustc_span::symbol::sym;
 use rustc_span::{self, MultiSpan, Span};
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
 pub fn check_wf_new(tcx: TyCtxt<'_>) {
@@ -26,7 +29,7 @@
 }
 
 pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
-    if !tcx.sess.target.target.is_abi_supported(abi) {
+    if !tcx.sess.target.is_abi_supported(abi) {
         struct_span_err!(
             tcx.sess,
             span,
@@ -345,8 +348,7 @@
     check_packed(tcx, span, def);
 }
 
-/// When the `#![feature(untagged_unions)]` gate is active,
-/// check that the fields of the `union` does not contain fields that need dropping.
+/// Check that the fields of the `union` do not need dropping.
 pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
     let item_type = tcx.type_of(item_def_id);
     if let ty::Adt(def, substs) = item_type.kind() {
@@ -385,7 +387,13 @@
     origin: &hir::OpaqueTyOrigin,
 ) {
     check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
-    check_opaque_for_cycles(tcx, def_id, substs, span, origin);
+    if tcx.type_of(def_id).references_error() {
+        return;
+    }
+    if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
+        return;
+    }
+    check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
 }
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -452,8 +460,7 @@
             ty: None,
         };
         let prohibit_opaque = tcx
-            .predicates_of(def_id)
-            .predicates
+            .explicit_item_bounds(def_id)
             .iter()
             .any(|(predicate, _)| predicate.visit_with(&mut visitor));
         debug!(
@@ -475,7 +482,7 @@
                 span,
                 E0760,
                 "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
-             a parent scope",
+                 a parent scope",
                 if is_async { "async fn" } else { "impl Trait" },
             );
 
@@ -503,7 +510,7 @@
     substs: SubstsRef<'tcx>,
     span: Span,
     origin: &hir::OpaqueTyOrigin,
-) {
+) -> Result<(), ErrorReported> {
     if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
     {
         match origin {
@@ -513,9 +520,82 @@
             }
             _ => opaque_type_cycle_error(tcx, def_id, span),
         }
+        Err(ErrorReported)
+    } else {
+        Ok(())
     }
 }
 
+/// Check that the concrete type behind `impl Trait` actually implements `Trait`.
+///
+/// This is mostly checked at the places that specify the opaque type, but we
+/// check those cases in the `param_env` of that function, which may have
+/// bounds not on this opaque type:
+///
+/// type X<T> = impl Clone
+/// fn f<T: Clone>(t: T) -> X<T> {
+///     t
+/// }
+///
+/// Without this check the above code is incorrectly accepted: we would ICE if
+/// some tried, for example, to clone an `Option<X<&mut ()>>`.
+fn check_opaque_meets_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    substs: SubstsRef<'tcx>,
+    span: Span,
+    origin: &hir::OpaqueTyOrigin,
+) {
+    match origin {
+        // Checked when type checking the function containing them.
+        hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return,
+        // Can have different predicates to their defining use
+        hir::OpaqueTyOrigin::Binding | hir::OpaqueTyOrigin::Misc => {}
+    }
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let param_env = tcx.param_env(def_id);
+
+    tcx.infer_ctxt().enter(move |infcx| {
+        let inh = Inherited::new(infcx, def_id);
+        let infcx = &inh.infcx;
+        let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+
+        let misc_cause = traits::ObligationCause::misc(span, hir_id);
+
+        let (_, opaque_type_map) = inh.register_infer_ok_obligations(
+            infcx.instantiate_opaque_types(def_id, hir_id, param_env, &opaque_ty, span),
+        );
+
+        for (def_id, opaque_defn) in opaque_type_map {
+            match infcx
+                .at(&misc_cause, param_env)
+                .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
+            {
+                Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
+                Err(ty_err) => tcx.sess.delay_span_bug(
+                    opaque_defn.definition_span,
+                    &format!(
+                        "could not unify `{}` with revealed type:\n{}",
+                        opaque_defn.concrete_ty, ty_err,
+                    ),
+                ),
+            }
+        }
+
+        // Check that all obligations are satisfied by the implementation's
+        // version.
+        if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+            infcx.report_fulfillment_errors(errors, None, false);
+        }
+
+        // Finally, resolve all regions. This catches wily misuses of
+        // lifetime parameters.
+        let fcx = FnCtxt::new(&inh, param_env, hir_id);
+        fcx.regionck_item(hir_id, span, &[]);
+    });
+}
+
 pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
     debug!(
         "check_item_type(it.hir_id={}, it.name={})",
@@ -552,9 +632,25 @@
 
             for item in items.iter() {
                 let item = tcx.hir().trait_item(item.id);
-                if let hir::TraitItemKind::Fn(sig, _) = &item.kind {
-                    let abi = sig.header.abi;
-                    fn_maybe_err(tcx, item.ident.span, abi);
+                match item.kind {
+                    hir::TraitItemKind::Fn(ref sig, _) => {
+                        let abi = sig.header.abi;
+                        fn_maybe_err(tcx, item.ident.span, abi);
+                    }
+                    hir::TraitItemKind::Type(.., Some(_default)) => {
+                        let item_def_id = tcx.hir().local_def_id(item.hir_id).to_def_id();
+                        let assoc_item = tcx.associated_item(item_def_id);
+                        let trait_substs =
+                            InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                        let _: Result<_, rustc_errors::ErrorReported> = check_type_bounds(
+                            tcx,
+                            assoc_item,
+                            assoc_item,
+                            item.span,
+                            ty::TraitRef { def_id: def_id.to_def_id(), substs: trait_substs },
+                        );
+                    }
+                    _ => {}
                 }
             }
         }
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 8898a54..8cd83c3 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -81,19 +81,10 @@
             self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
         );
 
-        let tupled_upvars_ty =
-            self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| {
-                upvars.iter().map(|(&var_hir_id, _)| {
-                    // Create type variables (for now) to represent the transformed
-                    // types of upvars. These will be unified during the upvar
-                    // inference phase (`upvar.rs`).
-                    self.infcx.next_ty_var(TypeVariableOrigin {
-                        // FIXME(eddyb) distinguish upvar inference variables from the rest.
-                        kind: TypeVariableOriginKind::ClosureSynthetic,
-                        span: self.tcx.hir().span(var_hir_id),
-                    })
-                })
-            }));
+        let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::ClosureSynthetic,
+            span: self.tcx.hir().span(expr.hir_id),
+        });
 
         if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
         {
@@ -201,6 +192,7 @@
                     obligation.predicate
                 );
 
+                let bound_predicate = obligation.predicate.bound_atom();
                 if let ty::PredicateAtom::Projection(proj_predicate) =
                     obligation.predicate.skip_binders()
                 {
@@ -208,7 +200,7 @@
                     // the complete signature.
                     self.deduce_sig_from_projection(
                         Some(obligation.cause.span),
-                        ty::Binder::bind(proj_predicate),
+                        bound_predicate.rebind(proj_predicate),
                     )
                 } else {
                     None
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 4addee1..6da3ecd 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -39,6 +39,7 @@
 use crate::check::FnCtxt;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
 use rustc_middle::ty::adjustment::{
@@ -221,11 +222,11 @@
                 // unsafe qualifier.
                 self.coerce_from_fn_pointer(a, a_f, b)
             }
-            ty::Closure(_, substs_a) => {
+            ty::Closure(closure_def_id_a, substs_a) => {
                 // Non-capturing closures are coercible to
                 // function pointers or unsafe function pointers.
                 // It cannot convert closures that require unsafe.
-                self.coerce_closure_to_fn(a, substs_a, b)
+                self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b)
             }
             _ => {
                 // Otherwise, just use unification rules.
@@ -582,7 +583,8 @@
         while !queue.is_empty() {
             let obligation = queue.remove(0);
             debug!("coerce_unsized resolve step: {:?}", obligation);
-            let trait_pred = match obligation.predicate.skip_binders() {
+            let bound_predicate = obligation.predicate.bound_atom();
+            let trait_pred = match bound_predicate.skip_binder() {
                 ty::PredicateAtom::Trait(trait_pred, _)
                     if traits.contains(&trait_pred.def_id()) =>
                 {
@@ -593,7 +595,7 @@
                             has_unsized_tuple_coercion = true;
                         }
                     }
-                    ty::Binder::bind(trait_pred)
+                    bound_predicate.rebind(trait_pred)
                 }
                 _ => {
                     coercion.obligations.push(obligation);
@@ -762,6 +764,7 @@
     fn coerce_closure_to_fn(
         &self,
         a: Ty<'tcx>,
+        closure_def_id_a: DefId,
         substs_a: SubstsRef<'tcx>,
         b: Ty<'tcx>,
     ) -> CoerceResult<'tcx> {
@@ -772,7 +775,18 @@
         let b = self.shallow_resolve(b);
 
         match b.kind() {
-            ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => {
+            // At this point we haven't done capture analysis, which means
+            // that the ClosureSubsts just contains an inference variable instead
+            // of tuple of captured types.
+            //
+            // All we care here is if any variable is being captured and not the exact paths,
+            // so we check `upvars_mentioned` for root variables being captured.
+            ty::FnPtr(fn_ty)
+                if self
+                    .tcx
+                    .upvars_mentioned(closure_def_id_a.expect_local())
+                    .map_or(true, |u| u.is_empty()) =>
+            {
                 // We coerce the closure, which has fn type
                 //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
                 // to
@@ -906,8 +920,8 @@
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
         let (a_sig, b_sig) = {
             let is_capturing_closure = |ty| {
-                if let &ty::Closure(_, substs) = ty {
-                    substs.as_closure().upvar_tys().next().is_some()
+                if let &ty::Closure(closure_def_id, _substs) = ty {
+                    self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some()
                 } else {
                     false
                 }
@@ -1461,6 +1475,28 @@
         if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
             self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output);
         }
+
+        if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
+            // If the closure has an explicit return type annotation,
+            // then a type error may occur at the first return expression we
+            // see in the closure (if it conflicts with the declared
+            // return type). Skip adding a note in this case, since it
+            // would be incorrect.
+            if !err.span.primary_spans().iter().any(|span| span == sp) {
+                let hir = fcx.tcx.hir();
+                let body_owner = hir.body_owned_by(hir.enclosing_body_owner(fcx.body_id));
+                if fcx.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) {
+                    err.span_note(
+                        *sp,
+                        &format!(
+                            "return type inferred to be `{}` here",
+                            fcx.resolve_vars_if_possible(&expected)
+                        ),
+                    );
+                }
+            }
+        }
+
         err
     }
 
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 7aa54e0..4acc745 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -5,6 +5,7 @@
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_infer::traits::util;
 use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
@@ -327,7 +328,7 @@
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
-        fcx.regionck_item(impl_m_hir_id, impl_m_span, &[]);
+        fcx.regionck_item(impl_m_hir_id, impl_m_span, trait_sig.inputs_and_output);
 
         Ok(())
     })
@@ -1052,7 +1053,7 @@
 
         compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
 
-        compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
+        check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
     })();
 }
 
@@ -1170,20 +1171,13 @@
 /// For default associated types the normalization is not possible (the value
 /// from the impl could be overridden). We also can't normalize generic
 /// associated types (yet) because they contain bound parameters.
-fn compare_projection_bounds<'tcx>(
+pub fn check_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ty: &ty::AssocItem,
     impl_ty: &ty::AssocItem,
     impl_ty_span: Span,
     impl_trait_ref: ty::TraitRef<'tcx>,
 ) -> Result<(), ErrorReported> {
-    let have_gats = tcx.features().generic_associated_types;
-    if impl_ty.defaultness.is_final() && !have_gats {
-        // For "final", non-generic associate type implementations, we
-        // don't need this as described above.
-        return Ok(());
-    }
-
     // Given
     //
     // impl<A, B> Foo<u32> for (A, B) {
@@ -1211,16 +1205,27 @@
     // ParamEnv for normalization specifically.
     let normalize_param_env = {
         let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
-        predicates.push(
-            ty::Binder::dummy(ty::ProjectionPredicate {
-                projection_ty: ty::ProjectionTy {
-                    item_def_id: trait_ty.def_id,
-                    substs: rebased_substs,
-                },
-                ty: impl_ty_value,
-            })
-            .to_predicate(tcx),
-        );
+        match impl_ty_value.kind() {
+            ty::Projection(proj)
+                if proj.item_def_id == trait_ty.def_id && proj.substs == rebased_substs =>
+            {
+                // Don't include this predicate if the projected type is
+                // exactly the same as the projection. This can occur in
+                // (somewhat dubious) code like this:
+                //
+                // impl<T> X for T where T: X { type Y = <T as X>::Y; }
+            }
+            _ => predicates.push(
+                ty::Binder::dummy(ty::ProjectionPredicate {
+                    projection_ty: ty::ProjectionTy {
+                        item_def_id: trait_ty.def_id,
+                        substs: rebased_substs,
+                    },
+                    ty: impl_ty_value,
+                })
+                .to_predicate(tcx),
+            ),
+        };
         ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
     };
 
@@ -1231,33 +1236,38 @@
 
         let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
         let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
-        let cause = ObligationCause::new(
-            impl_ty_span,
-            impl_ty_hir_id,
-            ObligationCauseCode::ItemObligation(trait_ty.def_id),
-        );
+        let mk_cause = |span| {
+            ObligationCause::new(
+                impl_ty_span,
+                impl_ty_hir_id,
+                ObligationCauseCode::BindingObligation(trait_ty.def_id, span),
+            )
+        };
 
-        let predicates = tcx.projection_predicates(trait_ty.def_id);
-        debug!("compare_projection_bounds: projection_predicates={:?}", predicates);
+        let obligations = tcx
+            .explicit_item_bounds(trait_ty.def_id)
+            .iter()
+            .map(|&(bound, span)| {
+                let concrete_ty_bound = bound.subst(tcx, rebased_substs);
+                debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
 
-        for predicate in predicates {
-            let concrete_ty_predicate = predicate.subst(tcx, rebased_substs);
-            debug!("compare_projection_bounds: concrete predicate = {:?}", concrete_ty_predicate);
+                traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
+            })
+            .collect();
+        debug!("check_type_bounds: item_bounds={:?}", obligations);
 
+        for mut obligation in util::elaborate_obligations(tcx, obligations) {
             let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
                 &mut selcx,
                 normalize_param_env,
                 normalize_cause.clone(),
-                &concrete_ty_predicate,
+                &obligation.predicate,
             );
             debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+            obligation.predicate = normalized_predicate;
 
             inh.register_predicates(obligations);
-            inh.register_predicate(traits::Obligation::new(
-                cause.clone(),
-                param_env,
-                normalized_predicate,
-            ));
+            inh.register_predicate(obligation);
         }
 
         // Check that all obligations are satisfied by the implementation's
@@ -1270,7 +1280,11 @@
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
-        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]);
+        let implied_bounds = match impl_ty.container {
+            ty::TraitContainer(_) => vec![],
+            ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span),
+        };
+        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &implied_bounds);
 
         Ok(())
     })
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 247bbf6..b814378 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -117,11 +117,10 @@
         ty
     }
 
-    // Checks that the type of `expr` can be coerced to `expected`.
-    //
-    // N.B., this code relies on `self.diverges` to be accurate. In
-    // particular, assignments to `!` will be permitted if the
-    // diverges flag is currently "always".
+    /// Checks that the type of `expr` can be coerced to `expected`.
+    ///
+    /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
+    /// will be permitted if the diverges flag is currently "always".
     pub fn demand_coerce_diag(
         &self,
         expr: &hir::Expr<'_>,
@@ -752,8 +751,20 @@
             }
         }
 
-        let msg = format!("you can convert an `{}` to `{}`", checked_ty, expected_ty);
-        let cast_msg = format!("you can cast an `{} to `{}`", checked_ty, expected_ty);
+        let msg = format!(
+            "you can convert {} `{}` to {} `{}`",
+            checked_ty.kind().article(),
+            checked_ty,
+            expected_ty.kind().article(),
+            expected_ty,
+        );
+        let cast_msg = format!(
+            "you can cast {} `{}` to {} `{}`",
+            checked_ty.kind().article(),
+            checked_ty,
+            expected_ty.kind().article(),
+            expected_ty,
+        );
         let lit_msg = format!(
             "change the type of the numeric literal from `{}` to `{}`",
             checked_ty, expected_ty,
@@ -815,7 +826,7 @@
                     let suggestion = format!("{}::from({})", checked_ty, lhs_src);
                     (lhs_expr.span, msg, suggestion)
                 } else {
-                    let msg = format!("{} and panic if the converted value wouldn't fit", msg);
+                    let msg = format!("{} and panic if the converted value doesn't fit", msg);
                     let suggestion =
                         format!("{}{}.try_into().unwrap()", prefix, with_opt_paren(&src));
                     (expr.span, msg, suggestion)
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index ae94a6d..5650b2c 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -226,12 +226,14 @@
         // could be extended easily also to the other `Predicate`.
         let predicate_matches_closure = |p: Predicate<'tcx>| {
             let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
-            match (predicate.skip_binders(), p.skip_binders()) {
+            let predicate = predicate.bound_atom();
+            let p = p.bound_atom();
+            match (predicate.skip_binder(), p.skip_binder()) {
                 (ty::PredicateAtom::Trait(a, _), ty::PredicateAtom::Trait(b, _)) => {
-                    relator.relate(ty::Binder::bind(a), ty::Binder::bind(b)).is_ok()
+                    relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
                 }
                 (ty::PredicateAtom::Projection(a), ty::PredicateAtom::Projection(b)) => {
-                    relator.relate(ty::Binder::bind(a), ty::Binder::bind(b)).is_ok()
+                    relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
                 }
                 _ => predicate == p,
             }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index af800ea..9990f86 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -286,6 +286,7 @@
             }
             ExprKind::DropTemps(ref e) => self.check_expr_with_expectation(e, expected),
             ExprKind::Array(ref args) => self.check_expr_array(args, expected, expr),
+            ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
             ExprKind::Repeat(ref element, ref count) => {
                 self.check_expr_repeat(element, count, expected, expr)
             }
@@ -1275,7 +1276,7 @@
 
     /// Report an error for a struct field expression when there are fields which aren't provided.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error: missing field `you_can_use_this_field` in initializer of `foo::Foo`
     ///  --> src/main.rs:8:5
     ///   |
@@ -1327,7 +1328,7 @@
 
     /// Report an error for a struct field expression when there are no visible fields.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
     ///  --> src/main.rs:8:5
     ///   |
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs
deleted file mode 100644
index 79d6c7d..0000000
--- a/compiler/rustc_typeck/src/check/fn_ctxt.rs
+++ /dev/null
@@ -1,3200 +0,0 @@
-// ignore-tidy-filelength
-// FIXME: This file seems to have too much functionality wrapped into it,
-// leading to it being too long.
-// Splitting this file may involve abstracting functionality into other files.
-
-use super::callee::{self, DeferredCallResolution};
-use super::coercion::{CoerceMany, DynamicCoerceMany};
-use super::method::{self, MethodCallee, SelfSource};
-use super::Expectation::*;
-use super::TupleArgumentsFlag::*;
-use super::{
-    potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables,
-    Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState,
-};
-use crate::astconv::{
-    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
-};
-
-use rustc_ast as ast;
-use rustc_ast::util::parser::ExprPrecedence;
-use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::ErrorReported;
-use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
-use rustc_hir as hir;
-use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath};
-use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
-use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_infer::infer::{self, InferOk, InferResult};
-use rustc_middle::hir::map::blocks::FnLikeNode;
-use rustc_middle::ty::adjustment::{
-    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
-};
-use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{
-    self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
-};
-use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef,
-    ToPredicate, Ty, TyCtxt, UserType,
-};
-use rustc_session::{lint, Session};
-use rustc_span::hygiene::DesugaringKind;
-use rustc_span::source_map::{original_sp, DUMMY_SP};
-use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{self, BytePos, MultiSpan, Span};
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
-};
-
-use std::cell::{Cell, RefCell};
-use std::collections::hash_map::Entry;
-use std::iter;
-use std::mem::replace;
-use std::ops::Deref;
-use std::slice;
-
-pub struct FnCtxt<'a, 'tcx> {
-    pub(super) body_id: hir::HirId,
-
-    /// The parameter environment used for proving trait obligations
-    /// in this function. This can change when we descend into
-    /// closures (as they bring new things into scope), hence it is
-    /// not part of `Inherited` (as of the time of this writing,
-    /// closures do not yet change the environment, but they will
-    /// eventually).
-    pub(super) param_env: ty::ParamEnv<'tcx>,
-
-    /// Number of errors that had been reported when we started
-    /// checking this function. On exit, if we find that *more* errors
-    /// have been reported, we will skip regionck and other work that
-    /// expects the types within the function to be consistent.
-    // FIXME(matthewjasper) This should not exist, and it's not correct
-    // if type checking is run in parallel.
-    err_count_on_creation: usize,
-
-    /// If `Some`, this stores coercion information for returned
-    /// expressions. If `None`, this is in a context where return is
-    /// inappropriate, such as a const expression.
-    ///
-    /// This is a `RefCell<DynamicCoerceMany>`, which means that we
-    /// can track all the return expressions and then use them to
-    /// compute a useful coercion from the set, similar to a match
-    /// expression or other branching context. You can use methods
-    /// like `expected_ty` to access the declared return type (if
-    /// any).
-    pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
-
-    pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
-
-    pub(super) ret_type_span: Option<Span>,
-
-    /// Used exclusively to reduce cost of advanced evaluation used for
-    /// more helpful diagnostics.
-    pub(super) in_tail_expr: bool,
-
-    /// First span of a return site that we find. Used in error messages.
-    pub(super) ret_coercion_span: RefCell<Option<Span>>,
-
-    pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
-
-    pub(super) ps: RefCell<UnsafetyState>,
-
-    /// Whether the last checked node generates a divergence (e.g.,
-    /// `return` will set this to `Always`). In general, when entering
-    /// an expression or other node in the tree, the initial value
-    /// indicates whether prior parts of the containing expression may
-    /// have diverged. It is then typically set to `Maybe` (and the
-    /// old value remembered) for processing the subparts of the
-    /// current expression. As each subpart is processed, they may set
-    /// the flag to `Always`, etc. Finally, at the end, we take the
-    /// result and "union" it with the original value, so that when we
-    /// return the flag indicates if any subpart of the parent
-    /// expression (up to and including this part) has diverged. So,
-    /// if you read it after evaluating a subexpression `X`, the value
-    /// you get indicates whether any subexpression that was
-    /// evaluating up to and including `X` diverged.
-    ///
-    /// We currently use this flag only for diagnostic purposes:
-    ///
-    /// - To warn about unreachable code: if, after processing a
-    ///   sub-expression but before we have applied the effects of the
-    ///   current node, we see that the flag is set to `Always`, we
-    ///   can issue a warning. This corresponds to something like
-    ///   `foo(return)`; we warn on the `foo()` expression. (We then
-    ///   update the flag to `WarnedAlways` to suppress duplicate
-    ///   reports.) Similarly, if we traverse to a fresh statement (or
-    ///   tail expression) from a `Always` setting, we will issue a
-    ///   warning. This corresponds to something like `{return;
-    ///   foo();}` or `{return; 22}`, where we would warn on the
-    ///   `foo()` or `22`.
-    ///
-    /// An expression represents dead code if, after checking it,
-    /// the diverges flag is set to something other than `Maybe`.
-    pub(super) diverges: Cell<Diverges>,
-
-    /// Whether any child nodes have any type errors.
-    pub(super) has_errors: Cell<bool>,
-
-    pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
-
-    pub(super) inh: &'a Inherited<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn new(
-        inh: &'a Inherited<'a, 'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
-    ) -> FnCtxt<'a, 'tcx> {
-        FnCtxt {
-            body_id,
-            param_env,
-            err_count_on_creation: inh.tcx.sess.err_count(),
-            ret_coercion: None,
-            ret_coercion_impl_trait: None,
-            ret_type_span: None,
-            in_tail_expr: false,
-            ret_coercion_span: RefCell::new(None),
-            resume_yield_tys: None,
-            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
-            diverges: Cell::new(Diverges::Maybe),
-            has_errors: Cell::new(false),
-            enclosing_breakables: RefCell::new(EnclosingBreakables {
-                stack: Vec::new(),
-                by_id: Default::default(),
-            }),
-            inh,
-        }
-    }
-
-    pub fn sess(&self) -> &Session {
-        &self.tcx.sess
-    }
-
-    pub fn errors_reported_since_creation(&self) -> bool {
-        self.tcx.sess.err_count() > self.err_count_on_creation
-    }
-
-    /// Produces warning on the given node, if the current point in the
-    /// function is unreachable, and there hasn't been another warning.
-    pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
-        // FIXME: Combine these two 'if' expressions into one once
-        // let chains are implemented
-        if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
-            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
-            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
-            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
-            if !span.is_desugaring(DesugaringKind::CondTemporary)
-                && !span.is_desugaring(DesugaringKind::Async)
-                && !orig_span.is_desugaring(DesugaringKind::Await)
-            {
-                self.diverges.set(Diverges::WarnedAlways);
-
-                debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
-
-                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
-                    let msg = format!("unreachable {}", kind);
-                    lint.build(&msg)
-                        .span_label(span, &msg)
-                        .span_label(
-                            orig_span,
-                            custom_note
-                                .unwrap_or("any code following this expression is unreachable"),
-                        )
-                        .emit();
-                })
-            }
-        }
-    }
-
-    pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
-        ObligationCause::new(span, self.body_id, code)
-    }
-
-    pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
-        self.cause(span, ObligationCauseCode::MiscObligation)
-    }
-
-    /// Resolves type and const variables in `ty` if possible. Unlike the infcx
-    /// version (resolve_vars_if_possible), this version will
-    /// also select obligations if it seems useful, in an effort
-    /// to get more type information.
-    pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_vars_with_obligations(ty={:?})", ty);
-
-        // No Infer()? Nothing needs doing.
-        if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
-            return ty;
-        }
-
-        // If `ty` is a type variable, see whether we already know what it is.
-        ty = self.resolve_vars_if_possible(&ty);
-        if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
-            return ty;
-        }
-
-        // If not, try resolving pending obligations as much as
-        // possible. This can help substantially when there are
-        // indirect dependencies that don't seem worth tracking
-        // precisely.
-        self.select_obligations_where_possible(false, |_| {});
-        ty = self.resolve_vars_if_possible(&ty);
-
-        debug!("resolve_vars_with_obligations: ty={:?}", ty);
-        ty
-    }
-
-    pub(super) fn record_deferred_call_resolution(
-        &self,
-        closure_def_id: DefId,
-        r: DeferredCallResolution<'tcx>,
-    ) {
-        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.entry(closure_def_id).or_default().push(r);
-    }
-
-    pub(super) fn remove_deferred_call_resolutions(
-        &self,
-        closure_def_id: DefId,
-    ) -> Vec<DeferredCallResolution<'tcx>> {
-        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
-    }
-
-    pub fn tag(&self) -> String {
-        format!("{:p}", self)
-    }
-
-    pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
-        self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
-            span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
-        })
-    }
-
-    #[inline]
-    pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
-        debug!(
-            "write_ty({:?}, {:?}) in fcx {}",
-            id,
-            self.resolve_vars_if_possible(&ty),
-            self.tag()
-        );
-        self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
-
-        if ty.references_error() {
-            self.has_errors.set(true);
-            self.set_tainted_by_errors();
-        }
-    }
-
-    pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
-        self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
-    }
-
-    fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) {
-        self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
-    }
-
-    pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
-        debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
-        self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
-        self.write_substs(hir_id, method.substs);
-
-        // When the method is confirmed, the `method.substs` includes
-        // parameters from not just the method, but also the impl of
-        // the method -- in particular, the `Self` type will be fully
-        // resolved. However, those are not something that the "user
-        // specified" -- i.e., those types come from the inferred type
-        // of the receiver, not something the user wrote. So when we
-        // create the user-substs, we want to replace those earlier
-        // types with just the types that the user actually wrote --
-        // that is, those that appear on the *method itself*.
-        //
-        // As an example, if the user wrote something like
-        // `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 !method.substs.is_noop() {
-            let method_generics = self.tcx.generics_of(method.def_id);
-            if !method_generics.params.is_empty() {
-                let user_type_annotation = self.infcx.probe(|_| {
-                    let user_substs = UserSubsts {
-                        substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
-                            let i = param.index as usize;
-                            if i < method_generics.parent_count {
-                                self.infcx.var_for_def(DUMMY_SP, param)
-                            } else {
-                                method.substs[i]
-                            }
-                        }),
-                        user_self_ty: None, // not relevant here
-                    };
-
-                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
-                        method.def_id,
-                        user_substs,
-                    ))
-                });
-
-                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
-                self.write_user_type_annotation(hir_id, user_type_annotation);
-            }
-        }
-    }
-
-    pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
-        if !substs.is_noop() {
-            debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
-
-            self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
-        }
-    }
-
-    /// Given the substs that we just converted from the HIR, try to
-    /// canonicalize them and store them as user-given substitutions
-    /// (i.e., substitutions that must be respected by the NLL check).
-    ///
-    /// This should be invoked **before any unifications have
-    /// occurred**, so that annotations like `Vec<_>` are preserved
-    /// properly.
-    pub fn write_user_type_annotation_from_substs(
-        &self,
-        hir_id: hir::HirId,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-        user_self_ty: Option<UserSelfTy<'tcx>>,
-    ) {
-        debug!(
-            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
-             user_self_ty={:?} in fcx {}",
-            hir_id,
-            def_id,
-            substs,
-            user_self_ty,
-            self.tag(),
-        );
-
-        if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
-            let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
-                def_id,
-                UserSubsts { substs, user_self_ty },
-            ));
-            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
-            self.write_user_type_annotation(hir_id, canonicalized);
-        }
-    }
-
-    pub fn write_user_type_annotation(
-        &self,
-        hir_id: hir::HirId,
-        canonical_user_type_annotation: CanonicalUserType<'tcx>,
-    ) {
-        debug!(
-            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
-            hir_id,
-            canonical_user_type_annotation,
-            self.tag(),
-        );
-
-        if !canonical_user_type_annotation.is_identity() {
-            self.typeck_results
-                .borrow_mut()
-                .user_provided_types_mut()
-                .insert(hir_id, canonical_user_type_annotation);
-        } else {
-            debug!("write_user_type_annotation: skipping identity substs");
-        }
-    }
-
-    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
-        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
-
-        if adj.is_empty() {
-            return;
-        }
-
-        let autoborrow_mut = adj.iter().any(|adj| {
-            matches!(adj, &Adjustment {
-                kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
-                ..
-            })
-        });
-
-        match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
-            Entry::Vacant(entry) => {
-                entry.insert(adj);
-            }
-            Entry::Occupied(mut entry) => {
-                debug!(" - composing on top of {:?}", entry.get());
-                match (&entry.get()[..], &adj[..]) {
-                    // Applying any adjustment on top of a NeverToAny
-                    // is a valid NeverToAny adjustment, because it can't
-                    // be reached.
-                    (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
-                    (&[
-                        Adjustment { kind: Adjust::Deref(_), .. },
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
-                    ], &[
-                        Adjustment { kind: Adjust::Deref(_), .. },
-                        .. // Any following adjustments are allowed.
-                    ]) => {
-                        // A reborrow has no effect before a dereference.
-                    }
-                    // FIXME: currently we never try to compose autoderefs
-                    // and ReifyFnPointer/UnsafeFnPointer, but we could.
-                    _ =>
-                        bug!("while adjusting {:?}, can't compose {:?} and {:?}",
-                             expr, entry.get(), adj)
-                };
-                *entry.get_mut() = adj;
-            }
-        }
-
-        // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
-        // In this case implicit use of `Deref` and `Index` within `<expr>` should
-        // instead be `DerefMut` and `IndexMut`, so fix those up.
-        if autoborrow_mut {
-            self.convert_place_derefs_to_mutable(expr);
-        }
-    }
-
-    /// Basically whenever we are converting from a type scheme into
-    /// the fn body space, we always want to normalize associated
-    /// types as well. This function combines the two.
-    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let value = value.subst(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &value);
-        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result);
-        result
-    }
-
-    /// As `instantiate_type_scheme`, but for the bounds found in a
-    /// generic type scheme.
-    fn instantiate_bounds(
-        &self,
-        span: Span,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-    ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
-        let bounds = self.tcx.predicates_of(def_id);
-        let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
-        let result = bounds.instantiate(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &result);
-        debug!(
-            "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
-            bounds, substs, result, spans,
-        );
-        (result, spans)
-    }
-
-    /// Replaces the opaque types from the given value with type variables,
-    /// and records the `OpaqueTypeMap` for later use during writeback. See
-    /// `InferCtxt::instantiate_opaque_types` for more details.
-    pub(super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
-        &self,
-        parent_id: hir::HirId,
-        value: &T,
-        value_span: Span,
-    ) -> T {
-        let parent_def_id = self.tcx.hir().local_def_id(parent_id);
-        debug!(
-            "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
-            parent_def_id, value
-        );
-
-        let (value, opaque_type_map) =
-            self.register_infer_ok_obligations(self.instantiate_opaque_types(
-                parent_def_id,
-                self.body_id,
-                self.param_env,
-                value,
-                value_span,
-            ));
-
-        let mut opaque_types = self.opaque_types.borrow_mut();
-        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
-        for (ty, decl) in opaque_type_map {
-            let _ = opaque_types.insert(ty, decl);
-            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
-        }
-
-        value
-    }
-
-    pub(super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
-    }
-
-    pub(super) fn normalize_associated_types_in_as_infer_ok<T>(
-        &self,
-        span: Span,
-        value: &T,
-    ) -> InferOk<'tcx, T>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value)
-    }
-
-    pub fn require_type_meets(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-        def_id: DefId,
-    ) {
-        self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
-    }
-
-    pub fn require_type_is_sized(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        if !ty.references_error() {
-            let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
-            self.require_type_meets(ty, span, code, lang_item);
-        }
-    }
-
-    pub fn require_type_is_sized_deferred(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        if !ty.references_error() {
-            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
-        }
-    }
-
-    pub fn register_bound(
-        &self,
-        ty: Ty<'tcx>,
-        def_id: DefId,
-        cause: traits::ObligationCause<'tcx>,
-    ) {
-        if !ty.references_error() {
-            self.fulfillment_cx.borrow_mut().register_bound(
-                self,
-                self.param_env,
-                ty,
-                def_id,
-                cause,
-            );
-        }
-    }
-
-    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
-        let t = AstConv::ast_ty_to_ty(self, ast_t);
-        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
-        t
-    }
-
-    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
-        let ty = self.to_ty(ast_ty);
-        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
-
-        if Self::can_contain_user_lifetime_bounds(ty) {
-            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
-            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
-            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
-        }
-
-        ty
-    }
-
-    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
-        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
-        let c = ty::Const::from_anon_const(self.tcx, const_def_id);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
-        );
-        c
-    }
-
-    pub fn const_arg_to_const(
-        &self,
-        ast_c: &hir::AnonConst,
-        param_def_id: DefId,
-    ) -> &'tcx ty::Const<'tcx> {
-        let const_def = ty::WithOptConstParam {
-            did: self.tcx.hir().local_def_id(ast_c.hir_id),
-            const_param_did: Some(param_def_id),
-        };
-        let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
-        );
-        c
-    }
-
-    // If the type given by the user has free regions, save it for later, since
-    // NLL would like to enforce those. Also pass in types that involve
-    // projections, since those can resolve to `'static` bounds (modulo #54940,
-    // which hopefully will be fixed by the time you see this comment, dear
-    // reader, although I have my doubts). Also pass in types with inference
-    // types, because they may be repeated. Other sorts of things are already
-    // sufficiently enforced with erased regions. =)
-    fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        t.has_free_regions() || t.has_projections() || t.has_infer_types()
-    }
-
-    pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
-        match self.typeck_results.borrow().node_types().get(id) {
-            Some(&t) => t,
-            None if self.is_tainted_by_errors() => self.tcx.ty_error(),
-            None => {
-                bug!(
-                    "no type for node {}: {} in fcx {}",
-                    id,
-                    self.tcx.hir().node_to_string(id),
-                    self.tag()
-                );
-            }
-        }
-    }
-
-    /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
-    pub fn register_wf_obligation(
-        &self,
-        arg: subst::GenericArg<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        // WF obligations never themselves fail, so no real need to give a detailed cause:
-        let cause = traits::ObligationCause::new(span, self.body_id, code);
-        self.register_predicate(traits::Obligation::new(
-            cause,
-            self.param_env,
-            ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
-        ));
-    }
-
-    /// Registers obligations that all `substs` are well-formed.
-    pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
-        for arg in substs.iter().filter(|arg| {
-            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
-        }) {
-            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
-        }
-    }
-
-    /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
-    /// type/region parameter was instantiated (`substs`), creates and registers suitable
-    /// trait/region obligations.
-    ///
-    /// For example, if there is a function:
-    ///
-    /// ```
-    /// fn foo<'a,T:'a>(...)
-    /// ```
-    ///
-    /// and a reference:
-    ///
-    /// ```
-    /// let f = foo;
-    /// ```
-    ///
-    /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
-    /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
-    pub fn add_obligations_for_parameters(
-        &self,
-        cause: traits::ObligationCause<'tcx>,
-        predicates: ty::InstantiatedPredicates<'tcx>,
-    ) {
-        assert!(!predicates.has_escaping_bound_vars());
-
-        debug!("add_obligations_for_parameters(predicates={:?})", predicates);
-
-        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
-            self.register_predicate(obligation);
-        }
-    }
-
-    // FIXME(arielb1): use this instead of field.ty everywhere
-    // Only for fields! Returns <none> for methods>
-    // Indifferent to privacy flags
-    pub fn field_ty(
-        &self,
-        span: Span,
-        field: &'tcx ty::FieldDef,
-        substs: SubstsRef<'tcx>,
-    ) -> Ty<'tcx> {
-        self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
-    }
-
-    pub(super) fn check_casts(&self) {
-        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
-        for cast in deferred_cast_checks.drain(..) {
-            cast.check(self);
-        }
-    }
-
-    pub(super) fn resolve_generator_interiors(&self, def_id: DefId) {
-        let mut generators = self.deferred_generator_interiors.borrow_mut();
-        for (body_id, interior, kind) in generators.drain(..) {
-            self.select_obligations_where_possible(false, |_| {});
-            super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
-        }
-    }
-
-    // Tries to apply a fallback to `ty` if it is an unsolved variable.
-    //
-    // - Unconstrained ints are replaced with `i32`.
-    //
-    // - Unconstrained floats are replaced with with `f64`.
-    //
-    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
-    //   is enabled. Otherwise, they are replaced with `()`.
-    //
-    // Fallback becomes very dubious if we have encountered type-checking errors.
-    // In that case, fallback to Error.
-    // The return value indicates whether fallback has occurred.
-    pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
-        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
-        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
-
-        assert!(ty.is_ty_infer());
-        let fallback = match self.type_is_unconstrained_numeric(ty) {
-            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
-            UnconstrainedInt => self.tcx.types.i32,
-            UnconstrainedFloat => self.tcx.types.f64,
-            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
-            Neither => {
-                // This type variable was created from the instantiation of an opaque
-                // type. The fact that we're attempting to perform fallback for it
-                // means that the function neither constrained it to a concrete
-                // type, nor to the opaque type itself.
-                //
-                // For example, in this code:
-                //
-                //```
-                // type MyType = impl Copy;
-                // fn defining_use() -> MyType { true }
-                // fn other_use() -> MyType { defining_use() }
-                // ```
-                //
-                // `defining_use` will constrain the instantiated inference
-                // variable to `bool`, while `other_use` will constrain
-                // the instantiated inference variable to `MyType`.
-                //
-                // When we process opaque types during writeback, we
-                // will handle cases like `other_use`, and not count
-                // them as defining usages
-                //
-                // However, we also need to handle cases like this:
-                //
-                // ```rust
-                // pub type Foo = impl Copy;
-                // fn produce() -> Option<Foo> {
-                //     None
-                //  }
-                //  ```
-                //
-                // In the above snippet, the inference variable created by
-                // instantiating `Option<Foo>` will be completely unconstrained.
-                // We treat this as a non-defining use by making the inference
-                // variable fall back to the opaque type itself.
-                if let FallbackMode::All = mode {
-                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
-                        debug!(
-                            "fallback_if_possible: falling back opaque type var {:?} to {:?}",
-                            ty, opaque_ty
-                        );
-                        *opaque_ty
-                    } else {
-                        return false;
-                    }
-                } else {
-                    return false;
-                }
-            }
-        };
-        debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
-        self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
-        true
-    }
-
-    pub(super) fn select_all_obligations_or_error(&self) {
-        debug!("select_all_obligations_or_error");
-        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
-            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
-        }
-    }
-
-    /// Select as many obligations as we can at present.
-    pub(super) fn select_obligations_where_possible(
-        &self,
-        fallback_has_occurred: bool,
-        mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
-    ) {
-        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
-        if let Err(mut errors) = result {
-            mutate_fullfillment_errors(&mut errors);
-            self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
-        }
-    }
-
-    /// For the overloaded place expressions (`*x`, `x[3]`), the trait
-    /// 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(super) fn make_overloaded_place_return_type(
-        &self,
-        method: MethodCallee<'tcx>,
-    ) -> ty::TypeAndMut<'tcx> {
-        // extract method return type, which will be &T;
-        let ret_ty = method.sig.output();
-
-        // method returns &T, but the type as visible to user is T, so deref
-        ret_ty.builtin_deref(true).unwrap()
-    }
-
-    pub(super) fn check_method_argument_types(
-        &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        method: Result<MethodCallee<'tcx>, ()>,
-        args_no_rcvr: &'tcx [hir::Expr<'tcx>],
-        tuple_arguments: TupleArgumentsFlag,
-        expected: Expectation<'tcx>,
-    ) -> Ty<'tcx> {
-        let has_error = match method {
-            Ok(method) => method.substs.references_error() || method.sig.references_error(),
-            Err(_) => true,
-        };
-        if has_error {
-            let err_inputs = self.err_args(args_no_rcvr.len());
-
-            let err_inputs = match tuple_arguments {
-                DontTupleArguments => err_inputs,
-                TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
-            };
-
-            self.check_argument_types(
-                sp,
-                expr,
-                &err_inputs[..],
-                &[],
-                args_no_rcvr,
-                false,
-                tuple_arguments,
-                None,
-            );
-            return self.tcx.ty_error();
-        }
-
-        let method = method.unwrap();
-        // HACK(eddyb) ignore self in the definition (see above).
-        let expected_arg_tys = self.expected_inputs_for_expected_output(
-            sp,
-            expected,
-            method.sig.output(),
-            &method.sig.inputs()[1..],
-        );
-        self.check_argument_types(
-            sp,
-            expr,
-            &method.sig.inputs()[1..],
-            &expected_arg_tys[..],
-            args_no_rcvr,
-            method.sig.c_variadic,
-            tuple_arguments,
-            self.tcx.hir().span_if_local(method.def_id),
-        );
-        method.sig.output()
-    }
-
-    fn self_type_matches_expected_vid(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        expected_vid: ty::TyVid,
-    ) -> bool {
-        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
-        debug!(
-            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
-            trait_ref, self_ty, expected_vid
-        );
-        match *self_ty.kind() {
-            ty::Infer(ty::TyVar(found_vid)) => {
-                // FIXME: consider using `sub_root_var` here so we
-                // can see through subtyping.
-                let found_vid = self.root_var(found_vid);
-                debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
-                expected_vid == found_vid
-            }
-            _ => false,
-        }
-    }
-
-    pub(super) fn obligations_for_self_ty<'b>(
-        &'b self,
-        self_ty: ty::TyVid,
-    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
-    + Captures<'tcx>
-    + 'b {
-        // FIXME: consider using `sub_root_var` here so we
-        // can see through subtyping.
-        let ty_var_root = self.root_var(self_ty);
-        debug!(
-            "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
-            self_ty,
-            ty_var_root,
-            self.fulfillment_cx.borrow().pending_obligations()
-        );
-
-        self.fulfillment_cx
-            .borrow()
-            .pending_obligations()
-            .into_iter()
-            .filter_map(move |obligation| {
-                match obligation.predicate.skip_binders() {
-                    ty::PredicateAtom::Projection(data) => {
-                        Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation))
-                    }
-                    ty::PredicateAtom::Trait(data, _) => {
-                        Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation))
-                    }
-                    ty::PredicateAtom::Subtype(..) => None,
-                    ty::PredicateAtom::RegionOutlives(..) => None,
-                    ty::PredicateAtom::TypeOutlives(..) => None,
-                    ty::PredicateAtom::WellFormed(..) => None,
-                    ty::PredicateAtom::ObjectSafe(..) => None,
-                    ty::PredicateAtom::ConstEvaluatable(..) => None,
-                    ty::PredicateAtom::ConstEquate(..) => None,
-                    // N.B., this predicate is created by breaking down a
-                    // `ClosureType: FnFoo()` predicate, where
-                    // `ClosureType` represents some `Closure`. It can't
-                    // possibly be referring to the current closure,
-                    // because we haven't produced the `Closure` for
-                    // this closure yet; this is exactly why the other
-                    // code is looking for a self type of a unresolved
-                    // inference variable.
-                    ty::PredicateAtom::ClosureKind(..) => None,
-                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
-                }
-            })
-            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
-    }
-
-    pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
-        self.obligations_for_self_ty(self_ty)
-            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
-    }
-
-    /// Generic function that factors out common logic from function calls,
-    /// method calls and overloaded operators.
-    pub(super) fn check_argument_types(
-        &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        fn_inputs: &[Ty<'tcx>],
-        expected_arg_tys: &[Ty<'tcx>],
-        args: &'tcx [hir::Expr<'tcx>],
-        c_variadic: bool,
-        tuple_arguments: TupleArgumentsFlag,
-        def_span: Option<Span>,
-    ) {
-        let tcx = self.tcx;
-        // Grab the argument types, supplying fresh type variables
-        // if the wrong number of arguments were supplied
-        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
-
-        // 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 fn_inputs.iter().zip(args.iter()) {
-            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
-        }
-
-        let expected_arg_count = fn_inputs.len();
-
-        let param_count_error = |expected_count: usize,
-                                 arg_count: usize,
-                                 error_code: &str,
-                                 c_variadic: bool,
-                                 sugg_unit: bool| {
-            let (span, start_span, args) = match &expr.kind {
-                hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
-                hir::ExprKind::MethodCall(path_segment, span, args, _) => (
-                    *span,
-                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
-                    path_segment
-                        .args
-                        .and_then(|args| args.args.iter().last())
-                        // Account for `foo.bar::<T>()`.
-                        .map(|arg| {
-                            // Skip the closing `>`.
-                            tcx.sess
-                                .source_map()
-                                .next_point(tcx.sess.source_map().next_point(arg.span()))
-                        })
-                        .unwrap_or(*span),
-                    &args[1..], // Skip the receiver.
-                ),
-                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
-            };
-            let arg_spans = if args.is_empty() {
-                // foo()
-                // ^^^-- supplied 0 arguments
-                // |
-                // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
-            } else {
-                // foo(1, 2, 3)
-                // ^^^ -  -  - supplied 3 arguments
-                // |
-                // expected 2 arguments
-                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
-            };
-
-            let mut err = tcx.sess.struct_span_err_with_code(
-                span,
-                &format!(
-                    "this function takes {}{} but {} {} supplied",
-                    if c_variadic { "at least " } else { "" },
-                    potentially_plural_count(expected_count, "argument"),
-                    potentially_plural_count(arg_count, "argument"),
-                    if arg_count == 1 { "was" } else { "were" }
-                ),
-                DiagnosticId::Error(error_code.to_owned()),
-            );
-            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
-            for (i, span) in arg_spans.into_iter().enumerate() {
-                err.span_label(
-                    span,
-                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
-                );
-            }
-
-            if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) {
-                err.span_label(def_s, "defined here");
-            }
-            if sugg_unit {
-                let sugg_span = tcx.sess.source_map().end_point(expr.span);
-                // remove closing `)` from the span
-                let sugg_span = sugg_span.shrink_to_lo();
-                err.span_suggestion(
-                    sugg_span,
-                    "expected the unit value `()`; create it with empty parentheses",
-                    String::from("()"),
-                    Applicability::MachineApplicable,
-                );
-            } else {
-                err.span_label(
-                    span,
-                    format!(
-                        "expected {}{}",
-                        if c_variadic { "at least " } else { "" },
-                        potentially_plural_count(expected_count, "argument")
-                    ),
-                );
-            }
-            err.emit();
-        };
-
-        let mut expected_arg_tys = expected_arg_tys.to_vec();
-
-        let formal_tys = if tuple_arguments == TupleArguments {
-            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
-            match tuple_type.kind() {
-                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
-                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
-                }
-                ty::Tuple(arg_types) => {
-                    expected_arg_tys = match expected_arg_tys.get(0) {
-                        Some(&ty) => match ty.kind() {
-                            ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
-                            _ => vec![],
-                        },
-                        None => vec![],
-                    };
-                    arg_types.iter().map(|k| k.expect_ty()).collect()
-                }
-                _ => {
-                    struct_span_err!(
-                        tcx.sess,
-                        sp,
-                        E0059,
-                        "cannot use call notation; the first type parameter \
-                         for the function trait is neither a tuple nor unit"
-                    )
-                    .emit();
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
-                }
-            }
-        } else if expected_arg_count == supplied_arg_count {
-            fn_inputs.to_vec()
-        } else if c_variadic {
-            if supplied_arg_count >= expected_arg_count {
-                fn_inputs.to_vec()
-            } else {
-                param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
-                expected_arg_tys = vec![];
-                self.err_args(supplied_arg_count)
-            }
-        } else {
-            // is the missing argument of type `()`?
-            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit()
-            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&fn_inputs[0]).is_unit()
-            } else {
-                false
-            };
-            param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
-
-            expected_arg_tys = vec![];
-            self.err_args(supplied_arg_count)
-        };
-
-        debug!(
-            "check_argument_types: formal_tys={:?}",
-            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
-        );
-
-        // If there is no expectation, expect formal_tys.
-        let expected_arg_tys =
-            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
-
-        let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
-
-        // Check the arguments.
-        // We do this in a pretty awful way: first we type-check any arguments
-        // that are not closures, then we type-check the closures. This is so
-        // that we have more information about the types of arguments when we
-        // type-check the functions. This isn't really the right way to do this.
-        for &check_closures in &[false, true] {
-            debug!("check_closures={}", check_closures);
-
-            // More awful hacks: before we check argument types, try to do
-            // an "opportunistic" trait resolution of any trait bounds on
-            // the call. This helps coercions.
-            if check_closures {
-                self.select_obligations_where_possible(false, |errors| {
-                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
-                    self.point_at_arg_instead_of_call_if_possible(
-                        errors,
-                        &final_arg_types[..],
-                        sp,
-                        &args,
-                    );
-                })
-            }
-
-            // For C-variadic functions, we don't have a declared type for all of
-            // the arguments hence we only do our usual type checking with
-            // the arguments who's types we do know.
-            let t = if c_variadic {
-                expected_arg_count
-            } else if tuple_arguments == TupleArguments {
-                args.len()
-            } else {
-                supplied_arg_count
-            };
-            for (i, arg) in args.iter().take(t).enumerate() {
-                // Warn only for the first loop (the "no closures" one).
-                // Closure arguments themselves can't be diverging, but
-                // a previous argument can, e.g., `foo(panic!(), || {})`.
-                if !check_closures {
-                    self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
-                }
-
-                let is_closure = match arg.kind {
-                    ExprKind::Closure(..) => true,
-                    _ => false,
-                };
-
-                if is_closure != check_closures {
-                    continue;
-                }
-
-                debug!("checking the argument");
-                let formal_ty = formal_tys[i];
-
-                // The special-cased logic below has three functions:
-                // 1. Provide as good of an expected type as possible.
-                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
-
-                let checked_ty = self.check_expr_with_expectation(&arg, expected);
-
-                // 2. Coerce to the most detailed type that could be coerced
-                //    to, which is `expected_ty` if `rvalue_hint` returns an
-                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
-                // We're processing function arguments so we definitely want to use
-                // two-phase borrows.
-                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-                final_arg_types.push((i, checked_ty, coerce_ty));
-
-                // 3. Relate the expected type and the formal one,
-                //    if the expected type was used for the coercion.
-                self.demand_suptype(arg.span, formal_ty, coerce_ty);
-            }
-        }
-
-        // We also need to make sure we at least write the ty of the other
-        // arguments which we skipped above.
-        if c_variadic {
-            fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
-                use crate::structured_errors::{StructuredDiagnostic, VariadicError};
-                VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
-            }
-
-            for arg in args.iter().skip(expected_arg_count) {
-                let arg_ty = self.check_expr(&arg);
-
-                // There are a few types which get autopromoted when passed via varargs
-                // in C but we just error out instead and require explicit casts.
-                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
-                match arg_ty.kind() {
-                    ty::Float(ast::FloatTy::F32) => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
-                    }
-                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
-                    }
-                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
-                    }
-                    ty::FnDef(..) => {
-                        let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
-                        let ptr_ty = self.resolve_vars_if_possible(&ptr_ty);
-                        variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
-                    }
-                    _ => {}
-                }
-            }
-        }
-    }
-
-    pub(super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-        vec![self.tcx.ty_error(); len]
-    }
-
-    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
-    /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
-    /// reference a type argument. The reason to walk also the checked type is that the coerced type
-    /// can be not easily comparable with predicate type (because of coercion). If the types match
-    /// for either checked or coerced type, and there's only *one* argument that does, we point at
-    /// the corresponding argument's expression span instead of the `fn` call path span.
-    fn point_at_arg_instead_of_call_if_possible(
-        &self,
-        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
-        call_sp: Span,
-        args: &'tcx [hir::Expr<'tcx>],
-    ) {
-        // We *do not* do this for desugared call spans to keep good diagnostics when involving
-        // the `?` operator.
-        if call_sp.desugaring_kind().is_some() {
-            return;
-        }
-
-        for error in errors {
-            // Only if the cause is somewhere inside the expression we want try to point at arg.
-            // Otherwise, it means that the cause is somewhere else and we should not change
-            // anything because we can break the correct span.
-            if !call_sp.contains(error.obligation.cause.span) {
-                continue;
-            }
-
-            if let ty::PredicateAtom::Trait(predicate, _) =
-                error.obligation.predicate.skip_binders()
-            {
-                // Collect the argument position for all arguments that could have caused this
-                // `FulfillmentError`.
-                let mut referenced_in = final_arg_types
-                    .iter()
-                    .map(|&(i, checked_ty, _)| (i, checked_ty))
-                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
-                    .flat_map(|(i, ty)| {
-                        let ty = self.resolve_vars_if_possible(&ty);
-                        // We walk the argument type because the argument's type could have
-                        // been `Option<T>`, but the `FulfillmentError` references `T`.
-                        if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
-                            Some(i)
-                        } else {
-                            None
-                        }
-                    })
-                    .collect::<Vec<usize>>();
-
-                // Both checked and coerced types could have matched, thus we need to remove
-                // duplicates.
-
-                // We sort primitive type usize here and can use unstable sort
-                referenced_in.sort_unstable();
-                referenced_in.dedup();
-
-                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
-                    // We make sure that only *one* argument matches the obligation failure
-                    // and we assign the obligation's span to its expression's.
-                    error.obligation.cause.make_mut().span = args[ref_in].span;
-                    error.points_at_arg_span = true;
-                }
-            }
-        }
-    }
-
-    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
-    /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
-    /// were caused by them. If they were, we point at the corresponding type argument's span
-    /// instead of the `fn` call path span.
-    fn point_at_type_arg_instead_of_call_if_possible(
-        &self,
-        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        call_expr: &'tcx hir::Expr<'tcx>,
-    ) {
-        if let hir::ExprKind::Call(path, _) = &call_expr.kind {
-            if let hir::ExprKind::Path(qpath) = &path.kind {
-                if let hir::QPath::Resolved(_, path) = &qpath {
-                    for error in errors {
-                        if let ty::PredicateAtom::Trait(predicate, _) =
-                            error.obligation.predicate.skip_binders()
-                        {
-                            // If any of the type arguments in this path segment caused the
-                            // `FullfillmentError`, point at its span (#61860).
-                            for arg in path
-                                .segments
-                                .iter()
-                                .filter_map(|seg| seg.args.as_ref())
-                                .flat_map(|a| a.args.iter())
-                            {
-                                if let hir::GenericArg::Type(hir_ty) = &arg {
-                                    if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
-                                        &hir_ty.kind
-                                    {
-                                        // Avoid ICE with associated types. As this is best
-                                        // effort only, it's ok to ignore the case. It
-                                        // would trigger in `is_send::<T::AssocType>();`
-                                        // from `typeck-default-trait-impl-assoc-type.rs`.
-                                    } else {
-                                        let ty = AstConv::ast_ty_to_ty(self, hir_ty);
-                                        let ty = self.resolve_vars_if_possible(&ty);
-                                        if ty == predicate.self_ty() {
-                                            error.obligation.cause.make_mut().span = hir_ty.span;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // AST fragment checking
-    pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> {
-        let tcx = self.tcx;
-
-        match lit.node {
-            ast::LitKind::Str(..) => tcx.mk_static_str(),
-            ast::LitKind::ByteStr(ref v) => {
-                tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
-            }
-            ast::LitKind::Byte(_) => tcx.types.u8,
-            ast::LitKind::Char(_) => tcx.types.char,
-            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
-            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
-            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
-                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
-                    ty::Int(_) | ty::Uint(_) => Some(ty),
-                    ty::Char => Some(tcx.types.u8),
-                    ty::RawPtr(..) => Some(tcx.types.usize),
-                    ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize),
-                    _ => None,
-                });
-                opt_ty.unwrap_or_else(|| self.next_int_var())
-            }
-            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
-            ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
-                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
-                    ty::Float(_) => Some(ty),
-                    _ => None,
-                });
-                opt_ty.unwrap_or_else(|| self.next_float_var())
-            }
-            ast::LitKind::Bool(_) => tcx.types.bool,
-            ast::LitKind::Err(_) => tcx.ty_error(),
-        }
-    }
-
-    /// Unifies the output type with the expected type early, for more coercions
-    /// and forward type information on the input expressions.
-    pub(super) fn expected_inputs_for_expected_output(
-        &self,
-        call_span: Span,
-        expected_ret: Expectation<'tcx>,
-        formal_ret: Ty<'tcx>,
-        formal_args: &[Ty<'tcx>],
-    ) -> Vec<Ty<'tcx>> {
-        let formal_ret = self.resolve_vars_with_obligations(formal_ret);
-        let ret_ty = match expected_ret.only_has_type(self) {
-            Some(ret) => ret,
-            None => return Vec::new(),
-        };
-        let expect_args = self
-            .fudge_inference_if_ok(|| {
-                // Attempt to apply a subtyping relationship between the formal
-                // return type (likely containing type variables if the function
-                // is polymorphic) and the expected return type.
-                // No argument expectations are produced if unification fails.
-                let origin = self.misc(call_span);
-                let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
-
-                // FIXME(#27336) can't use ? here, Try::from_error doesn't default
-                // to identity so the resulting type is not constrained.
-                match ures {
-                    Ok(ok) => {
-                        // Process any obligations locally as much as
-                        // we can.  We don't care if some things turn
-                        // out unconstrained or ambiguous, as we're
-                        // just trying to get hints here.
-                        self.save_and_restore_in_snapshot_flag(|_| {
-                            let mut fulfill = TraitEngine::new(self.tcx);
-                            for obligation in ok.obligations {
-                                fulfill.register_predicate_obligation(self, obligation);
-                            }
-                            fulfill.select_where_possible(self)
-                        })
-                        .map_err(|_| ())?;
-                    }
-                    Err(_) => return Err(()),
-                }
-
-                // Record all the argument types, with the substitutions
-                // produced from the above subtyping unification.
-                Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect())
-            })
-            .unwrap_or_default();
-        debug!(
-            "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
-            formal_args, formal_ret, expect_args, expected_ret
-        );
-        expect_args
-    }
-
-    pub fn check_struct_path(
-        &self,
-        qpath: &QPath<'_>,
-        hir_id: hir::HirId,
-    ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
-        let path_span = qpath.qself_span();
-        let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
-        let variant = match def {
-            Res::Err => {
-                self.set_tainted_by_errors();
-                return None;
-            }
-            Res::Def(DefKind::Variant, _) => match ty.kind() {
-                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
-                _ => bug!("unexpected type: {:?}", ty),
-            },
-            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
-            | Res::SelfTy(..) => match ty.kind() {
-                ty::Adt(adt, substs) if !adt.is_enum() => {
-                    Some((adt.non_enum_variant(), adt.did, substs))
-                }
-                _ => None,
-            },
-            _ => bug!("unexpected definition: {:?}", def),
-        };
-
-        if let Some((variant, did, substs)) = variant {
-            debug!("check_struct_path: did={:?} substs={:?}", did, substs);
-            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
-
-            // Check bounds on type arguments used in the path.
-            let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
-            let cause =
-                traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
-            self.add_obligations_for_parameters(cause, bounds);
-
-            Some((variant, ty))
-        } else {
-            struct_span_err!(
-                self.tcx.sess,
-                path_span,
-                E0071,
-                "expected struct, variant or union type, found {}",
-                ty.sort_string(self.tcx)
-            )
-            .span_label(path_span, "not a struct")
-            .emit();
-            None
-        }
-    }
-
-    // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
-    // The newly resolved definition is written into `type_dependent_defs`.
-    fn finish_resolving_struct_path(
-        &self,
-        qpath: &QPath<'_>,
-        path_span: Span,
-        hir_id: hir::HirId,
-    ) -> (Res, Ty<'tcx>) {
-        match *qpath {
-            QPath::Resolved(ref maybe_qself, ref path) => {
-                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
-                let ty = AstConv::res_to_ty(self, self_ty, path, true);
-                (path.res, ty)
-            }
-            QPath::TypeRelative(ref qself, ref segment) => {
-                let ty = self.to_ty(qself);
-
-                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
-                let result =
-                    AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
-                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
-                let result = result.map(|(_, kind, def_id)| (kind, def_id));
-
-                // Write back the new resolution.
-                self.write_resolution(hir_id, result);
-
-                (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
-            }
-            QPath::LangItem(lang_item, span) => {
-                self.resolve_lang_item_path(lang_item, span, hir_id)
-            }
-        }
-    }
-
-    pub(super) fn resolve_lang_item_path(
-        &self,
-        lang_item: hir::LangItem,
-        span: Span,
-        hir_id: hir::HirId,
-    ) -> (Res, Ty<'tcx>) {
-        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
-        let def_kind = self.tcx.def_kind(def_id);
-
-        let item_ty = if let DefKind::Variant = def_kind {
-            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
-        } else {
-            self.tcx.type_of(def_id)
-        };
-        let substs = self.infcx.fresh_substs_for_item(span, def_id);
-        let ty = item_ty.subst(self.tcx, substs);
-
-        self.write_resolution(hir_id, Ok((def_kind, def_id)));
-        self.add_required_obligations(span, def_id, &substs);
-        (Res::Def(def_kind, def_id), ty)
-    }
-
-    /// Resolves an associated value path into a base type and associated constant, or method
-    /// resolution. The newly resolved definition is written into `type_dependent_defs`.
-    pub fn resolve_ty_and_res_ufcs<'b>(
-        &self,
-        qpath: &'b QPath<'b>,
-        hir_id: hir::HirId,
-        span: Span,
-    ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
-        debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
-        let (ty, qself, item_segment) = match *qpath {
-            QPath::Resolved(ref opt_qself, ref path) => {
-                return (
-                    path.res,
-                    opt_qself.as_ref().map(|qself| self.to_ty(qself)),
-                    &path.segments[..],
-                );
-            }
-            QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
-            QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
-        };
-        if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
-        {
-            // 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(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err);
-            return (def, Some(ty), slice::from_ref(&**item_segment));
-        }
-        let item_name = item_segment.ident;
-        let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| {
-            let result = match error {
-                method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
-                _ => Err(ErrorReported),
-            };
-            if item_name.name != kw::Invalid {
-                if let Some(mut e) = self.report_method_error(
-                    span,
-                    ty,
-                    item_name,
-                    SelfSource::QPath(qself),
-                    error,
-                    None,
-                ) {
-                    e.emit();
-                }
-            }
-            result
-        });
-
-        // Write back the new resolution.
-        self.write_resolution(hir_id, result);
-        (
-            result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err),
-            Some(ty),
-            slice::from_ref(&**item_segment),
-        )
-    }
-
-    pub fn check_decl_initializer(
-        &self,
-        local: &'tcx hir::Local<'tcx>,
-        init: &'tcx hir::Expr<'tcx>,
-    ) -> Ty<'tcx> {
-        // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed
-        // for #42640 (default match binding modes).
-        //
-        // See #44848.
-        let ref_bindings = local.pat.contains_explicit_ref_binding();
-
-        let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty;
-        if let Some(m) = ref_bindings {
-            // Somewhat subtle: if we have a `ref` binding in the pattern,
-            // we want to avoid introducing coercions for the RHS. This is
-            // both because it helps preserve sanity and, in the case of
-            // ref mut, for soundness (issue #23116). In particular, in
-            // the latter case, we need to be clear that the type of the
-            // referent for the reference that results is *equal to* the
-            // type of the place it is referencing, and not some
-            // supertype thereof.
-            let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
-            self.demand_eqtype(init.span, local_ty, init_ty);
-            init_ty
-        } else {
-            self.check_expr_coercable_to_type(init, local_ty, None)
-        }
-    }
-
-    /// Type check a `let` statement.
-    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
-        // Determine and write the type which we'll check the pattern against.
-        let ty = self.local_ty(local.span, local.hir_id).decl_ty;
-        self.write_ty(local.hir_id, ty);
-
-        // Type check the initializer.
-        if let Some(ref init) = local.init {
-            let init_ty = self.check_decl_initializer(local, &init);
-            self.overwrite_local_ty_if_err(local, ty, init_ty);
-        }
-
-        // Does the expected pattern type originate from an expression and what is the span?
-        let (origin_expr, ty_span) = match (local.ty, local.init) {
-            (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
-            (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
-            _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
-        };
-
-        // Type check the pattern. Override if necessary to avoid knock-on errors.
-        self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
-        let pat_ty = self.node_ty(local.pat.hir_id);
-        self.overwrite_local_ty_if_err(local, ty, pat_ty);
-    }
-
-    fn overwrite_local_ty_if_err(
-        &self,
-        local: &'tcx hir::Local<'tcx>,
-        decl_ty: Ty<'tcx>,
-        ty: Ty<'tcx>,
-    ) {
-        if ty.references_error() {
-            // Override the types everywhere with `err()` to avoid knock on errors.
-            self.write_ty(local.hir_id, ty);
-            self.write_ty(local.pat.hir_id, ty);
-            let local_ty = LocalTy { decl_ty, revealed_ty: ty };
-            self.locals.borrow_mut().insert(local.hir_id, local_ty);
-            self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
-        }
-    }
-
-    pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) {
-        err.span_suggestion_short(
-            span.shrink_to_hi(),
-            "consider using a semicolon here",
-            ";".to_string(),
-            Applicability::MachineApplicable,
-        );
-    }
-
-    pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
-        // Don't do all the complex logic below for `DeclItem`.
-        match stmt.kind {
-            hir::StmtKind::Item(..) => return,
-            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
-        }
-
-        self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
-
-        // Hide the outer diverging and `has_errors` flags.
-        let old_diverges = self.diverges.replace(Diverges::Maybe);
-        let old_has_errors = self.has_errors.replace(false);
-
-        match stmt.kind {
-            hir::StmtKind::Local(ref l) => {
-                self.check_decl_local(&l);
-            }
-            // Ignore for now.
-            hir::StmtKind::Item(_) => {}
-            hir::StmtKind::Expr(ref expr) => {
-                // Check with expected type of `()`.
-                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
-                    self.suggest_semicolon_at_end(expr.span, err);
-                });
-            }
-            hir::StmtKind::Semi(ref expr) => {
-                self.check_expr(&expr);
-            }
-        }
-
-        // Combine the diverging and `has_error` flags.
-        self.diverges.set(self.diverges.get() | old_diverges);
-        self.has_errors.set(self.has_errors.get() | old_has_errors);
-    }
-
-    pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
-        let unit = self.tcx.mk_unit();
-        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
-
-        // if the block produces a `!` value, that can always be
-        // (effectively) coerced to unit.
-        if !ty.is_never() {
-            self.demand_suptype(blk.span, unit, ty);
-        }
-    }
-
-    /// 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:
-    /// ```text
-    /// if false { return 0i32; } else { 1u32 }
-    /// //                               ^^^^ point at this instead of the whole `if` expression
-    /// ```
-    fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
-        if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
-            let arm_spans: Vec<Span> = arms
-                .iter()
-                .filter_map(|arm| {
-                    self.in_progress_typeck_results
-                        .and_then(|typeck_results| {
-                            typeck_results.borrow().node_type_opt(arm.body.hir_id)
-                        })
-                        .and_then(|arm_ty| {
-                            if arm_ty.is_never() {
-                                None
-                            } else {
-                                Some(match &arm.body.kind {
-                                    // Point at the tail expression when possible.
-                                    hir::ExprKind::Block(block, _) => {
-                                        block.expr.as_ref().map(|e| e.span).unwrap_or(block.span)
-                                    }
-                                    _ => arm.body.span,
-                                })
-                            }
-                        })
-                })
-                .collect();
-            if arm_spans.len() == 1 {
-                return arm_spans[0];
-            }
-        }
-        expr.span
-    }
-
-    pub(super) fn check_block_with_expected(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected: Expectation<'tcx>,
-    ) -> Ty<'tcx> {
-        let prev = {
-            let mut fcx_ps = self.ps.borrow_mut();
-            let unsafety_state = fcx_ps.recurse(blk);
-            replace(&mut *fcx_ps, unsafety_state)
-        };
-
-        // In some cases, blocks have just one exit, but other blocks
-        // can be targeted by multiple breaks. This can happen both
-        // with labeled blocks as well as when we desugar
-        // a `try { ... }` expression.
-        //
-        // Example 1:
-        //
-        //    'a: { if true { break 'a Err(()); } Ok(()) }
-        //
-        // Here we would wind up with two coercions, one from
-        // `Err(())` and the other from the tail expression
-        // `Ok(())`. If the tail expression is omitted, that's a
-        // "forced unit" -- unless the block diverges, in which
-        // case we can ignore the tail expression (e.g., `'a: {
-        // break 'a 22; }` would not force the type of the block
-        // to be `()`).
-        let tail_expr = blk.expr.as_ref();
-        let coerce_to_ty = expected.coercion_target_type(self, blk.span);
-        let coerce = if blk.targeted_by_break {
-            CoerceMany::new(coerce_to_ty)
-        } else {
-            let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
-                Some(e) => slice::from_ref(e),
-                None => &[],
-            };
-            CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
-        };
-
-        let prev_diverges = self.diverges.get();
-        let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
-
-        let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
-            for s in blk.stmts {
-                self.check_stmt(s);
-            }
-
-            // check the tail expression **without** holding the
-            // `enclosing_breakables` lock below.
-            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
-
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
-            let coerce = ctxt.coerce.as_mut().unwrap();
-            if let Some(tail_expr_ty) = tail_expr_ty {
-                let tail_expr = tail_expr.unwrap();
-                let span = self.get_expr_coercion_span(tail_expr);
-                let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
-                coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
-            } else {
-                // Subtle: if there is no explicit tail expression,
-                // that is typically equivalent to a tail expression
-                // of `()` -- except if the block diverges. In that
-                // case, there is no value supplied from the tail
-                // expression (assuming there are no other breaks,
-                // this implies that the type of the block will be
-                // `!`).
-                //
-                // #41425 -- label the implicit `()` as being the
-                // "found type" here, rather than the "expected type".
-                if !self.diverges.get().is_always() {
-                    // #50009 -- Do not point at the entire fn block span, point at the return type
-                    // span, as it is the cause of the requirement, and
-                    // `consider_hint_about_removing_semicolon` will point at the last expression
-                    // if it were a relevant part of the error. This improves usability in editors
-                    // 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) {
-                        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
-                            // output would otherwise be incorrect and even misleading. Make sure
-                            // the span we're aiming at correspond to a `fn` body.
-                            if block_sp == blk.span {
-                                sp = ret_sp;
-                                fn_span = Some(ident.span);
-                            }
-                        }
-                    }
-                    coerce.coerce_forced_unit(
-                        self,
-                        &self.misc(sp),
-                        &mut |err| {
-                            if let Some(expected_ty) = expected.only_has_type(self) {
-                                self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
-                            }
-                            if let Some(fn_span) = fn_span {
-                                err.span_label(
-                                    fn_span,
-                                    "implicitly returns `()` as its body has no tail or `return` \
-                                     expression",
-                                );
-                            }
-                        },
-                        false,
-                    );
-                }
-            }
-        });
-
-        if ctxt.may_break {
-            // If we can break from the block, then the block's exit is always reachable
-            // (... as long as the entry is reachable) - regardless of the tail of the block.
-            self.diverges.set(prev_diverges);
-        }
-
-        let mut ty = ctxt.coerce.unwrap().complete(self);
-
-        if self.has_errors.get() || ty.references_error() {
-            ty = self.tcx.ty_error()
-        }
-
-        self.write_ty(blk.hir_id, ty);
-
-        *self.ps.borrow_mut() = prev;
-        ty
-    }
-
-    fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
-        let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
-        match node {
-            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
-            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
-                let body = self.tcx.hir().body(body_id);
-                if let ExprKind::Block(block, _) = &body.value.kind {
-                    return Some(block.span);
-                }
-            }
-            _ => {}
-        }
-        None
-    }
-
-    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
-    fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
-        let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id));
-        self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
-    }
-
-    /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
-    pub(super) fn get_node_fn_decl(
-        &self,
-        node: Node<'tcx>,
-    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
-        match node {
-            Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
-                // 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((&sig.decl, ident, ident.name != sym::main))
-            }
-            Node::TraitItem(&hir::TraitItem {
-                ident,
-                kind: hir::TraitItemKind::Fn(ref sig, ..),
-                ..
-            }) => Some((&sig.decl, ident, true)),
-            Node::ImplItem(&hir::ImplItem {
-                ident,
-                kind: hir::ImplItemKind::Fn(ref sig, ..),
-                ..
-            }) => Some((&sig.decl, ident, false)),
-            _ => None,
-        }
-    }
-
-    /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
-    /// suggestion can be made, `None` otherwise.
-    pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'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().get(blk_id);
-            self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
-        })
-    }
-
-    /// On implicit return expressions with mismatched types, provides the following suggestions:
-    ///
-    /// - Points out the method's return type as the reason for the expected type.
-    /// - Possible missing semicolon.
-    /// - Possible missing return type if the return type is the default, and not `fn main()`.
-    pub fn suggest_mismatched_types_on_tail(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &'tcx hir::Expr<'tcx>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        cause_span: Span,
-        blk_id: hir::HirId,
-    ) -> bool {
-        let expr = expr.peel_drop_temps();
-        self.suggest_missing_semicolon(err, expr, expected, cause_span);
-        let mut pointing_at_return_type = false;
-        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
-            pointing_at_return_type =
-                self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
-        }
-        pointing_at_return_type
-    }
-
-    /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
-    /// the ctor would successfully solve the type mismatch and if so, suggest it:
-    /// ```
-    /// fn foo(x: usize) -> usize { x }
-    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
-    /// ```
-    fn suggest_fn_call(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) -> bool {
-        let hir = self.tcx.hir();
-        let (def_id, sig) = match *found.kind() {
-            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
-            _ => return false,
-        };
-
-        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0;
-        let sig = self.normalize_associated_types_in(expr.span, &sig);
-        if self.can_coerce(sig.output(), expected) {
-            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
-                (String::new(), Applicability::MachineApplicable)
-            } else {
-                ("...".to_string(), Applicability::HasPlaceholders)
-            };
-            let mut msg = "call this function";
-            match hir.get_if_local(def_id) {
-                Some(
-                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
-                    | Node::ImplItem(hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(_, body_id), ..
-                    })
-                    | Node::TraitItem(hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
-                        ..
-                    }),
-                ) => {
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Expr(hir::Expr {
-                    kind: ExprKind::Closure(_, _, body_id, _, _),
-                    span: full_closure_span,
-                    ..
-                })) => {
-                    if *full_closure_span == expr.span {
-                        return false;
-                    }
-                    msg = "call this closure";
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
-                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                    match def_id.as_local().map(|def_id| hir.def_kind(def_id)) {
-                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
-                            msg = "instantiate this tuple variant";
-                        }
-                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
-                            msg = "instantiate this tuple struct";
-                        }
-                        _ => {}
-                    }
-                }
-                Some(Node::ForeignItem(hir::ForeignItem {
-                    kind: hir::ForeignItemKind::Fn(_, idents, _),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                Some(Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                _ => {}
-            }
-            err.span_suggestion_verbose(
-                expr.span.shrink_to_hi(),
-                &format!("use parentheses to {}", msg),
-                format!("({})", sugg_call),
-                applicability,
-            );
-            return true;
-        }
-        false
-    }
-
-    pub fn suggest_deref_ref_or_into(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
-    ) {
-        if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
-            err.span_suggestion(sp, msg, suggestion, applicability);
-        } else if let (ty::FnDef(def_id, ..), true) =
-            (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
-        {
-            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
-                let sp = self.sess().source_map().guess_head_span(sp);
-                err.span_label(sp, &format!("{} defined here", found));
-            }
-        } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
-            let is_struct_pat_shorthand_field =
-                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
-            let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
-            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
-                let mut suggestions = iter::repeat(&expr_text)
-                    .zip(methods.iter())
-                    .filter_map(|(receiver, method)| {
-                        let method_call = format!(".{}()", method.ident);
-                        if receiver.ends_with(&method_call) {
-                            None // do not suggest code that is already there (#53348)
-                        } else {
-                            let method_call_list = [".to_vec()", ".to_string()"];
-                            let sugg = if receiver.ends_with(".clone()")
-                                && method_call_list.contains(&method_call.as_str())
-                            {
-                                let max_len = receiver.rfind('.').unwrap();
-                                format!("{}{}", &receiver[..max_len], method_call)
-                            } else {
-                                if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
-                                    format!("({}){}", receiver, method_call)
-                                } else {
-                                    format!("{}{}", receiver, method_call)
-                                }
-                            };
-                            Some(if is_struct_pat_shorthand_field {
-                                format!("{}: {}", receiver, sugg)
-                            } else {
-                                sugg
-                            })
-                        }
-                    })
-                    .peekable();
-                if suggestions.peek().is_some() {
-                    err.span_suggestions(
-                        expr.span,
-                        "try using a conversion method",
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-        }
-    }
-
-    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
-    /// in the heap by calling `Box::new()`.
-    pub(super) fn suggest_boxing_when_appropriate(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return;
-        }
-        if !expected.is_box() || found.is_box() {
-            return;
-        }
-        let boxed_found = self.tcx.mk_box(found);
-        if let (true, Ok(snippet)) = (
-            self.can_coerce(boxed_found, expected),
-            self.sess().source_map().span_to_snippet(expr.span),
-        ) {
-            err.span_suggestion(
-                expr.span,
-                "store this in the heap by calling `Box::new`",
-                format!("Box::new({})", snippet),
-                Applicability::MachineApplicable,
-            );
-            err.note(
-                "for more on the distinction between the stack and the heap, read \
-                 https://doc.rust-lang.org/book/ch15-01-box.html, \
-                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
-                 https://doc.rust-lang.org/std/boxed/index.html",
-            );
-        }
-    }
-
-    pub(super) fn note_internal_mutation_in_method(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        if found != self.tcx.types.unit {
-            return;
-        }
-        if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
-            if self
-                .typeck_results
-                .borrow()
-                .expr_ty_adjusted_opt(rcvr)
-                .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
-            {
-                return;
-            }
-            let mut sp = MultiSpan::from_span(path_segment.ident.span);
-            sp.push_span_label(
-                path_segment.ident.span,
-                format!(
-                    "this call modifies {} in-place",
-                    match rcvr.kind {
-                        ExprKind::Path(QPath::Resolved(
-                            None,
-                            hir::Path { segments: [segment], .. },
-                        )) => format!("`{}`", segment.ident),
-                        _ => "its receiver".to_string(),
-                    }
-                ),
-            );
-            sp.push_span_label(
-                rcvr.span,
-                "you probably want to use this value after calling the method...".to_string(),
-            );
-            err.span_note(
-                sp,
-                &format!("method `{}` modifies its receiver in-place", path_segment.ident),
-            );
-            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
-        }
-    }
-
-    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
-    pub(super) fn suggest_calling_boxed_future_when_appropriate(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) -> bool {
-        // Handle #68197.
-
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return false;
-        }
-        let pin_did = self.tcx.lang_items().pin_type();
-        match expected.kind() {
-            ty::Adt(def, _) if Some(def.did) != pin_did => return false,
-            // This guards the `unwrap` and `mk_box` below.
-            _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
-            _ => {}
-        }
-        let boxed_found = self.tcx.mk_box(found);
-        let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
-        if let (true, Ok(snippet)) = (
-            self.can_coerce(new_found, expected),
-            self.sess().source_map().span_to_snippet(expr.span),
-        ) {
-            match found.kind() {
-                ty::Adt(def, _) if def.is_box() => {
-                    err.help("use `Box::pin`");
-                }
-                _ => {
-                    err.span_suggestion(
-                        expr.span,
-                        "you need to pin and box this expression",
-                        format!("Box::pin({})", snippet),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            true
-        } else {
-            false
-        }
-    }
-
-    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
-    ///
-    /// ```
-    /// fn foo() {
-    ///     bar_that_returns_u32()
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the return expression in a block would make sense on its own as a
-    /// statement and the return type has been left as default or has been specified as `()`. If so,
-    /// it suggests adding a semicolon.
-    fn suggest_missing_semicolon(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expression: &'tcx hir::Expr<'tcx>,
-        expected: Ty<'tcx>,
-        cause_span: Span,
-    ) {
-        if expected.is_unit() {
-            // `BlockTailExpression` only relevant if the tail expr would be
-            // useful on its own.
-            match expression.kind {
-                ExprKind::Call(..)
-                | ExprKind::MethodCall(..)
-                | ExprKind::Loop(..)
-                | ExprKind::Match(..)
-                | ExprKind::Block(..) => {
-                    err.span_suggestion(
-                        cause_span.shrink_to_hi(),
-                        "try adding a semicolon",
-                        ";".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                _ => (),
-            }
-        }
-    }
-
-    /// A possible error is to forget to add a return type that is needed:
-    ///
-    /// ```
-    /// fn foo() {
-    ///     bar_that_returns_u32()
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the return type is left as default, the method is not part of an
-    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
-    /// type.
-    pub(super) fn suggest_missing_return_type(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        fn_decl: &hir::FnDecl<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        can_suggest: bool,
-    ) -> bool {
-        // Only suggest changing the return type for methods that
-        // haven't set a return type at all (and aren't `fn main()` or an impl).
-        match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
-            (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
-                err.span_suggestion(
-                    span,
-                    "try adding a return type",
-                    format!("-> {} ", self.resolve_vars_with_obligations(found)),
-                    Applicability::MachineApplicable,
-                );
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
-                err.span_label(span, "possibly return type missing here?");
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
-                // `fn main()` must return `()`, do not suggest changing return type
-                err.span_label(span, "expected `()` because of default return type");
-                true
-            }
-            // expectation was caused by something else, not the default return
-            (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
-            (&hir::FnRetTy::Return(ref ty), _, _, _) => {
-                // Only point to return type if the expected type is the return type, as if they
-                // are not, the expectation must have been caused by something else.
-                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
-                let sp = ty.span;
-                let ty = AstConv::ast_ty_to_ty(self, ty);
-                debug!("suggest_missing_return_type: return type {:?}", ty);
-                debug!("suggest_missing_return_type: expected type {:?}", ty);
-                if ty.kind() == expected.kind() {
-                    err.span_label(sp, format!("expected `{}` because of return type", expected));
-                    return true;
-                }
-                false
-            }
-        }
-    }
-
-    /// A possible error is to forget to add `.await` when using futures:
-    ///
-    /// ```
-    /// async fn make_u32() -> u32 {
-    ///     22
-    /// }
-    ///
-    /// fn take_u32(x: u32) {}
-    ///
-    /// async fn foo() {
-    ///     let x = make_u32();
-    ///     take_u32(x);
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
-    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
-    /// `.await` to the tail of the expression.
-    pub(super) fn suggest_missing_await(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
-        // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
-        // body isn't `async`.
-        let item_id = self.tcx().hir().get_parent_node(self.body_id);
-        if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
-            let body = self.tcx().hir().body(body_id);
-            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
-                let sp = expr.span;
-                // Check for `Future` implementations by constructing a predicate to
-                // prove: `<T as Future>::Output == U`
-                let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
-                let item_def_id = self
-                    .tcx
-                    .associated_items(future_trait)
-                    .in_definition_order()
-                    .next()
-                    .unwrap()
-                    .def_id;
-                // `<T as Future>::Output`
-                let projection_ty = ty::ProjectionTy {
-                    // `T`
-                    substs: self
-                        .tcx
-                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
-                    // `Future::Output`
-                    item_def_id,
-                };
-
-                let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
-                    projection_ty,
-                    ty: expected,
-                })
-                .potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
-                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
-
-                debug!("suggest_missing_await: trying obligation {:?}", obligation);
-
-                if self.infcx.predicate_may_hold(&obligation) {
-                    debug!("suggest_missing_await: obligation held: {:?}", obligation);
-                    if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
-                        err.span_suggestion(
-                            sp,
-                            "consider using `.await` here",
-                            format!("{}.await", code),
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        debug!("suggest_missing_await: no snippet for {:?}", sp);
-                    }
-                } else {
-                    debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
-                }
-            }
-        }
-    }
-
-    pub(super) fn suggest_missing_parentheses(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-    ) {
-        let sp = self.tcx.sess.source_map().start_point(expr.span);
-        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
-            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
-            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
-        }
-    }
-
-    pub(super) fn note_need_for_fn_pointer(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
-            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
-                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
-                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
-                if sig1 != sig2 {
-                    return;
-                }
-                err.note(
-                    "different `fn` items always have unique types, even if their signatures are \
-                     the same",
-                );
-                (sig1, *did1, substs1)
-            }
-            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
-                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
-                if sig1 != *sig2 {
-                    return;
-                }
-                (sig1, *did, substs)
-            }
-            _ => return,
-        };
-        err.help(&format!("change the expected type to be function pointer `{}`", sig));
-        err.help(&format!(
-            "if the expected type is due to type inference, cast the expected `fn` to a function \
-             pointer: `{} as {}`",
-            self.tcx.def_path_str_with_substs(did, substs),
-            sig
-        ));
-    }
-
-    /// A common error is to add an extra semicolon:
-    ///
-    /// ```
-    /// fn foo() -> usize {
-    ///     22;
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the final statement in a block is an
-    /// expression with an explicit semicolon whose type is compatible
-    /// with `expected_ty`. If so, it suggests removing the semicolon.
-    fn consider_hint_about_removing_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-        err: &mut DiagnosticBuilder<'_>,
-    ) {
-        if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
-            err.span_suggestion(
-                span_semi,
-                "consider removing this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    pub(super) fn could_remove_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-    ) -> Option<Span> {
-        // Be helpful when the user wrote `{... expr;}` and
-        // taking the `;` off is enough to fix the error.
-        let last_stmt = blk.stmts.last()?;
-        let last_expr = match last_stmt.kind {
-            hir::StmtKind::Semi(ref e) => e,
-            _ => return None,
-        };
-        let last_expr_ty = self.node_ty(last_expr.hir_id);
-        if matches!(last_expr_ty.kind(), ty::Error(_))
-            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
-        {
-            return None;
-        }
-        let original_span = original_sp(last_stmt.span, blk.span);
-        Some(original_span.with_lo(original_span.hi() - BytePos(1)))
-    }
-
-    // Instantiates the given path, which must refer to an item with the given
-    // number of type parameters and type.
-    pub fn instantiate_value_path(
-        &self,
-        segments: &[hir::PathSegment<'_>],
-        self_ty: Option<Ty<'tcx>>,
-        res: Res,
-        span: Span,
-        hir_id: hir::HirId,
-    ) -> (Ty<'tcx>, Res) {
-        debug!(
-            "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})",
-            segments, self_ty, res, hir_id,
-        );
-
-        let tcx = self.tcx;
-
-        let path_segs = match res {
-            Res::Local(_) | Res::SelfCtor(_) => vec![],
-            Res::Def(kind, def_id) => {
-                AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id)
-            }
-            _ => bug!("instantiate_value_path on {:?}", res),
-        };
-
-        let mut user_self_ty = None;
-        let mut is_alias_variant_ctor = false;
-        match res {
-            Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
-                if let Some(self_ty) = self_ty {
-                    let adt_def = self_ty.ty_adt_def().unwrap();
-                    user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
-                    is_alias_variant_ctor = true;
-                }
-            }
-            Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
-                let container = tcx.associated_item(def_id).container;
-                debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
-                match container {
-                    ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(tcx, span, None, trait_did)
-                    }
-                    ty::ImplContainer(impl_def_id) => {
-                        if segments.len() == 1 {
-                            // `<T>::assoc` will end up here, and so
-                            // can `T::assoc`. It this came from an
-                            // inherent impl, we need to record the
-                            // `T` for posterity (see `UserSelfTy` for
-                            // details).
-                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
-                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
-                        }
-                    }
-                }
-            }
-            _ => {}
-        }
-
-        // Now that we have categorized what space the parameters for each
-        // segment belong to, let's sort out the parameters that the user
-        // provided (if any) into their appropriate spaces. We'll also report
-        // errors if type parameters are provided in an inappropriate place.
-
-        let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
-        let generics_has_err = AstConv::prohibit_generics(
-            self,
-            segments.iter().enumerate().filter_map(|(index, seg)| {
-                if !generic_segs.contains(&index) || is_alias_variant_ctor {
-                    Some(seg)
-                } else {
-                    None
-                }
-            }),
-        );
-
-        if let Res::Local(hid) = res {
-            let ty = self.local_ty(span, hid).decl_ty;
-            let ty = self.normalize_associated_types_in(span, &ty);
-            self.write_ty(hir_id, ty);
-            return (ty, res);
-        }
-
-        if generics_has_err {
-            // Don't try to infer type parameters when prohibited generic arguments were given.
-            user_self_ty = None;
-        }
-
-        // Now we have to compare the types that the user *actually*
-        // provided against the types that were *expected*. If the user
-        // did not provide any types, then we want to substitute inference
-        // variables. If the user provided some types, we may still need
-        // to add defaults. If the user provided *too many* types, that's
-        // a problem.
-
-        let mut infer_args_for_err = FxHashSet::default();
-        for &PathSeg(def_id, index) in &path_segs {
-            let seg = &segments[index];
-            let generics = tcx.generics_of(def_id);
-            // Argument-position `impl Trait` is treated as a normal generic
-            // parameter internally, but we don't allow users to specify the
-            // parameter's value explicitly, so we have to do some error-
-            // checking here.
-            if let GenericArgCountResult {
-                correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }),
-                ..
-            } = AstConv::check_generic_arg_count_for_call(
-                tcx, span, &generics, &seg, false, // `is_method_call`
-            ) {
-                infer_args_for_err.insert(index);
-                self.set_tainted_by_errors(); // See issue #53251.
-            }
-        }
-
-        let has_self = path_segs
-            .last()
-            .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
-            .unwrap_or(false);
-
-        let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
-            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
-            match *ty.kind() {
-                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
-                    let variant = adt_def.non_enum_variant();
-                    let ctor_def_id = variant.ctor_def_id.unwrap();
-                    (
-                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
-                        Some(substs),
-                    )
-                }
-                _ => {
-                    let mut err = tcx.sess.struct_span_err(
-                        span,
-                        "the `Self` constructor can only be used with tuple or unit structs",
-                    );
-                    if let Some(adt_def) = ty.ty_adt_def() {
-                        match adt_def.adt_kind() {
-                            AdtKind::Enum => {
-                                err.help("did you mean to use one of the enum's variants?");
-                            }
-                            AdtKind::Struct | AdtKind::Union => {
-                                err.span_suggestion(
-                                    span,
-                                    "use curly brackets",
-                                    String::from("Self { /* fields */ }"),
-                                    Applicability::HasPlaceholders,
-                                );
-                            }
-                        }
-                    }
-                    err.emit();
-
-                    return (tcx.ty_error(), res);
-                }
-            }
-        } else {
-            (res, None)
-        };
-        let def_id = res.def_id();
-
-        // The things we are substituting into the type should not contain
-        // escaping late-bound regions, and nor should the base type scheme.
-        let ty = tcx.type_of(def_id);
-
-        let arg_count = GenericArgCountResult {
-            explicit_late_bound: ExplicitLateBound::No,
-            correct: if infer_args_for_err.is_empty() {
-                Ok(())
-            } else {
-                Err(GenericArgCountMismatch::default())
-            },
-        };
-
-        let substs = self_ctor_substs.unwrap_or_else(|| {
-            AstConv::create_substs_for_generic_args(
-                tcx,
-                def_id,
-                &[][..],
-                has_self,
-                self_ty,
-                arg_count,
-                // Provide the generic args, and whether types should be inferred.
-                |def_id| {
-                    if let Some(&PathSeg(_, index)) =
-                        path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
-                    {
-                        // If we've encountered an `impl Trait`-related error, we're just
-                        // going to infer the arguments for better error messages.
-                        if !infer_args_for_err.contains(&index) {
-                            // Check whether the user has provided generic arguments.
-                            if let Some(ref data) = segments[index].args {
-                                return (Some(data), segments[index].infer_args);
-                            }
-                        }
-                        return (None, segments[index].infer_args);
-                    }
-
-                    (None, true)
-                },
-                // Provide substitutions for parameters for which (valid) arguments have been provided.
-                |param, arg| match (&param.kind, arg) {
-                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        AstConv::ast_region_to_region(self, lt, Some(param)).into()
-                    }
-                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.to_ty(ty).into()
-                    }
-                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                        self.const_arg_to_const(&ct.value, param.def_id).into()
-                    }
-                    _ => unreachable!(),
-                },
-                // Provide substitutions for parameters for which arguments are inferred.
-                |substs, param, infer_args| {
-                    match param.kind {
-                        GenericParamDefKind::Lifetime => {
-                            self.re_infer(Some(param), span).unwrap().into()
-                        }
-                        GenericParamDefKind::Type { has_default, .. } => {
-                            if !infer_args && has_default {
-                                // If we have a default, then we it doesn't matter that we're not
-                                // inferring the type arguments: we provide the default where any
-                                // is missing.
-                                let default = tcx.type_of(param.def_id);
-                                self.normalize_ty(
-                                    span,
-                                    default.subst_spanned(tcx, substs.unwrap(), Some(span)),
-                                )
-                                .into()
-                            } else {
-                                // If no type arguments were provided, we have to infer them.
-                                // This case also occurs as a result of some malformed input, e.g.
-                                // a lifetime argument being given instead of a type parameter.
-                                // Using inference instead of `Error` gives better error messages.
-                                self.var_for_def(span, param)
-                            }
-                        }
-                        GenericParamDefKind::Const => {
-                            // FIXME(const_generics:defaults)
-                            // No const parameters were provided, we have to infer them.
-                            self.var_for_def(span, param)
-                        }
-                    }
-                },
-            )
-        });
-        assert!(!substs.has_escaping_bound_vars());
-        assert!(!ty.has_escaping_bound_vars());
-
-        // First, store the "user substs" for later.
-        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
-
-        self.add_required_obligations(span, def_id, &substs);
-
-        // Substitute the values for the type parameters into the type of
-        // the referenced item.
-        let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
-
-        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
-            // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
-            // is inherent, there is no `Self` parameter; instead, the impl needs
-            // type parameters, which we can infer by unifying the provided `Self`
-            // with the substituted impl type.
-            // This also occurs for an enum variant on a type alias.
-            let ty = tcx.type_of(impl_def_id);
-
-            let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
-            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
-                Ok(ok) => self.register_infer_ok_obligations(ok),
-                Err(_) => {
-                    self.tcx.sess.delay_span_bug(
-                        span,
-                        &format!(
-                        "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
-                        self_ty,
-                        impl_ty,
-                    ),
-                    );
-                }
-            }
-        }
-
-        self.check_rustc_args_require_const(def_id, hir_id, span);
-
-        debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
-        self.write_substs(hir_id, substs);
-
-        (ty_substituted, res)
-    }
-
-    /// Add all the obligations that are required, substituting and normalized appropriately.
-    fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
-        let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
-
-        for (i, mut obligation) in traits::predicates_for_generics(
-            traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
-            self.param_env,
-            bounds,
-        )
-        .enumerate()
-        {
-            // This makes the error point at the bound, but we want to point at the argument
-            if let Some(span) = spans.get(i) {
-                obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
-            }
-            self.register_predicate(obligation);
-        }
-    }
-
-    fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) {
-        // We're only interested in functions tagged with
-        // #[rustc_args_required_const], so ignore anything that's not.
-        if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
-            return;
-        }
-
-        // If our calling expression is indeed the function itself, we're good!
-        // If not, generate an error that this can only be called directly.
-        if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) {
-            if let ExprKind::Call(ref callee, ..) = expr.kind {
-                if callee.hir_id == hir_id {
-                    return;
-                }
-            }
-        }
-
-        self.tcx.sess.span_err(
-            span,
-            "this function can only be invoked directly, not through a function pointer",
-        );
-    }
-
-    /// Resolves `typ` by a single level if `typ` is a type variable.
-    /// If no resolution is possible, then an error is reported.
-    /// Numeric inference variables may be left unresolved.
-    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let ty = self.resolve_vars_with_obligations(ty);
-        if !ty.is_ty_var() {
-            ty
-        } else {
-            if !self.is_tainted_by_errors() {
-                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
-                    .note("type must be known at this point")
-                    .emit();
-            }
-            let err = self.tcx.ty_error();
-            self.demand_suptype(sp, err, ty);
-            err
-        }
-    }
-
-    pub(super) fn with_breakable_ctxt<F: FnOnce() -> R, R>(
-        &self,
-        id: hir::HirId,
-        ctxt: BreakableCtxt<'tcx>,
-        f: F,
-    ) -> (BreakableCtxt<'tcx>, R) {
-        let index;
-        {
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            index = enclosing_breakables.stack.len();
-            enclosing_breakables.by_id.insert(id, index);
-            enclosing_breakables.stack.push(ctxt);
-        }
-        let result = f();
-        let ctxt = {
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            debug_assert!(enclosing_breakables.stack.len() == index + 1);
-            enclosing_breakables.by_id.remove(&id).expect("missing breakable context");
-            enclosing_breakables.stack.pop().expect("missing breakable context")
-        };
-        (ctxt, result)
-    }
-
-    /// Instantiate a QueryResponse in a probe context, without a
-    /// good ObligationCause.
-    pub(super) fn probe_instantiate_query_response(
-        &self,
-        span: Span,
-        original_values: &OriginalQueryValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
-    ) -> InferResult<'tcx, Ty<'tcx>> {
-        self.instantiate_query_response_and_region_obligations(
-            &traits::ObligationCause::misc(span, self.body_id),
-            self.param_env,
-            original_values,
-            query_result,
-        )
-    }
-
-    /// Returns `true` if an expression is contained inside the LHS of an assignment expression.
-    pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
-        let mut contained_in_place = false;
-
-        while let hir::Node::Expr(parent_expr) =
-            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
-        {
-            match &parent_expr.kind {
-                hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
-                    if lhs.hir_id == expr_id {
-                        contained_in_place = true;
-                        break;
-                    }
-                }
-                _ => (),
-            }
-            expr_id = parent_expr.hir_id;
-        }
-
-        contained_in_place
-    }
-}
-impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
-    type Target = Inherited<'a, 'tcx>;
-    fn deref(&self) -> &Self::Target {
-        &self.inh
-    }
-}
-
-impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn item_def_id(&self) -> Option<DefId> {
-        None
-    }
-
-    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
-        // FIXME: refactor this into a method
-        let node = self.tcx.hir().get(self.body_id);
-        if let Some(fn_like) = FnLikeNode::from_node(node) {
-            fn_like.constness()
-        } else {
-            hir::Constness::NotConst
-        }
-    }
-
-    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
-        let tcx = self.tcx;
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-        let item_id = tcx.hir().ty_param_owner(hir_id);
-        let item_def_id = tcx.hir().local_def_id(item_id);
-        let generics = tcx.generics_of(item_def_id);
-        let index = generics.param_def_id_to_index[&def_id];
-        ty::GenericPredicates {
-            parent: None,
-            predicates: tcx.arena.alloc_from_iter(
-                self.param_env.caller_bounds().iter().filter_map(|predicate| {
-                    match predicate.skip_binders() {
-                        ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
-                            // HACK(eddyb) should get the original `Span`.
-                            let span = tcx.def_span(def_id);
-                            Some((predicate, span))
-                        }
-                        _ => None,
-                    }
-                }),
-            ),
-        }
-    }
-
-    fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
-        let v = match def {
-            Some(def) => infer::EarlyBoundRegion(span, def.name),
-            None => infer::MiscVariable(span),
-        };
-        Some(self.next_region_var(v))
-    }
-
-    fn allow_ty_infer(&self) -> bool {
-        true
-    }
-
-    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
-        if let Some(param) = param {
-            if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
-                return ty;
-            }
-            unreachable!()
-        } else {
-            self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::TypeInference,
-                span,
-            })
-        }
-    }
-
-    fn ct_infer(
-        &self,
-        ty: Ty<'tcx>,
-        param: Option<&ty::GenericParamDef>,
-        span: Span,
-    ) -> &'tcx Const<'tcx> {
-        if let Some(param) = param {
-            if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
-                return ct;
-            }
-            unreachable!()
-        } else {
-            self.next_const_var(
-                ty,
-                ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
-            )
-        }
-    }
-
-    fn projected_ty_from_poly_trait_ref(
-        &self,
-        span: Span,
-        item_def_id: DefId,
-        item_segment: &hir::PathSegment<'_>,
-        poly_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Ty<'tcx> {
-        let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
-            span,
-            infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
-            &poly_trait_ref,
-        );
-
-        let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
-            self,
-            self.tcx,
-            span,
-            item_def_id,
-            item_segment,
-            trait_ref.substs,
-        );
-
-        self.tcx().mk_projection(item_def_id, item_substs)
-    }
-
-    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if ty.has_escaping_bound_vars() {
-            ty // FIXME: normalization and escaping regions
-        } else {
-            self.normalize_associated_types_in(span, &ty)
-        }
-    }
-
-    fn set_tainted_by_errors(&self) {
-        self.infcx.set_tainted_by_errors()
-    }
-
-    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
-        self.write_ty(hir_id, ty)
-    }
-}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
new file mode 100644
index 0000000..017b0ab
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -0,0 +1,1469 @@
+use crate::astconv::{
+    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
+};
+use crate::check::callee::{self, DeferredCallResolution};
+use crate::check::method::{self, MethodCallee, SelfSource};
+use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy};
+
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
+use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
+use rustc_infer::infer::{InferOk, InferResult};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::{
+    self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
+};
+use rustc_middle::ty::{
+    self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
+    Ty, UserType,
+};
+use rustc_session::lint;
+use rustc_span::hygiene::DesugaringKind;
+use rustc_span::source_map::{original_sp, DUMMY_SP};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::{self, BytePos, MultiSpan, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt};
+
+use std::collections::hash_map::Entry;
+use std::slice;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// Produces warning on the given node, if the current point in the
+    /// function is unreachable, and there hasn't been another warning.
+    pub(in super::super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
+        // FIXME: Combine these two 'if' expressions into one once
+        // let chains are implemented
+        if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
+            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
+            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
+            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
+            if !span.is_desugaring(DesugaringKind::CondTemporary)
+                && !span.is_desugaring(DesugaringKind::Async)
+                && !orig_span.is_desugaring(DesugaringKind::Await)
+            {
+                self.diverges.set(Diverges::WarnedAlways);
+
+                debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
+
+                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
+                    let msg = format!("unreachable {}", kind);
+                    lint.build(&msg)
+                        .span_label(span, &msg)
+                        .span_label(
+                            orig_span,
+                            custom_note
+                                .unwrap_or("any code following this expression is unreachable"),
+                        )
+                        .emit();
+                })
+            }
+        }
+    }
+
+    /// Resolves type and const variables in `ty` if possible. Unlike the infcx
+    /// version (resolve_vars_if_possible), this version will
+    /// also select obligations if it seems useful, in an effort
+    /// to get more type information.
+    pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+        debug!("resolve_vars_with_obligations(ty={:?})", ty);
+
+        // No Infer()? Nothing needs doing.
+        if !ty.has_infer_types_or_consts() {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            return ty;
+        }
+
+        // If `ty` is a type variable, see whether we already know what it is.
+        ty = self.resolve_vars_if_possible(&ty);
+        if !ty.has_infer_types_or_consts() {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            return ty;
+        }
+
+        // If not, try resolving pending obligations as much as
+        // possible. This can help substantially when there are
+        // indirect dependencies that don't seem worth tracking
+        // precisely.
+        self.select_obligations_where_possible(false, |_| {});
+        ty = self.resolve_vars_if_possible(&ty);
+
+        debug!("resolve_vars_with_obligations: ty={:?}", ty);
+        ty
+    }
+
+    pub(in super::super) fn record_deferred_call_resolution(
+        &self,
+        closure_def_id: DefId,
+        r: DeferredCallResolution<'tcx>,
+    ) {
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
+        deferred_call_resolutions.entry(closure_def_id).or_default().push(r);
+    }
+
+    pub(in super::super) fn remove_deferred_call_resolutions(
+        &self,
+        closure_def_id: DefId,
+    ) -> Vec<DeferredCallResolution<'tcx>> {
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
+        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
+    }
+
+    pub fn tag(&self) -> String {
+        format!("{:p}", self)
+    }
+
+    pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
+        self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
+            span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
+        })
+    }
+
+    #[inline]
+    pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
+        debug!(
+            "write_ty({:?}, {:?}) in fcx {}",
+            id,
+            self.resolve_vars_if_possible(&ty),
+            self.tag()
+        );
+        self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
+
+        if ty.references_error() {
+            self.has_errors.set(true);
+            self.set_tainted_by_errors();
+        }
+    }
+
+    pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
+        self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
+    }
+
+    pub(in super::super) fn write_resolution(
+        &self,
+        hir_id: hir::HirId,
+        r: Result<(DefKind, DefId), ErrorReported>,
+    ) {
+        self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
+    }
+
+    pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
+        debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
+        self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
+        self.write_substs(hir_id, method.substs);
+
+        // When the method is confirmed, the `method.substs` includes
+        // parameters from not just the method, but also the impl of
+        // the method -- in particular, the `Self` type will be fully
+        // resolved. However, those are not something that the "user
+        // specified" -- i.e., those types come from the inferred type
+        // of the receiver, not something the user wrote. So when we
+        // create the user-substs, we want to replace those earlier
+        // types with just the types that the user actually wrote --
+        // that is, those that appear on the *method itself*.
+        //
+        // As an example, if the user wrote something like
+        // `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 !method.substs.is_noop() {
+            let method_generics = self.tcx.generics_of(method.def_id);
+            if !method_generics.params.is_empty() {
+                let user_type_annotation = self.infcx.probe(|_| {
+                    let user_substs = UserSubsts {
+                        substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
+                            let i = param.index as usize;
+                            if i < method_generics.parent_count {
+                                self.infcx.var_for_def(DUMMY_SP, param)
+                            } else {
+                                method.substs[i]
+                            }
+                        }),
+                        user_self_ty: None, // not relevant here
+                    };
+
+                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+                        method.def_id,
+                        user_substs,
+                    ))
+                });
+
+                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
+                self.write_user_type_annotation(hir_id, user_type_annotation);
+            }
+        }
+    }
+
+    pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
+        if !substs.is_noop() {
+            debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
+
+            self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
+        }
+    }
+
+    /// Given the substs that we just converted from the HIR, try to
+    /// canonicalize them and store them as user-given substitutions
+    /// (i.e., substitutions that must be respected by the NLL check).
+    ///
+    /// This should be invoked **before any unifications have
+    /// occurred**, so that annotations like `Vec<_>` are preserved
+    /// properly.
+    pub fn write_user_type_annotation_from_substs(
+        &self,
+        hir_id: hir::HirId,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        user_self_ty: Option<UserSelfTy<'tcx>>,
+    ) {
+        debug!(
+            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
+             user_self_ty={:?} in fcx {}",
+            hir_id,
+            def_id,
+            substs,
+            user_self_ty,
+            self.tag(),
+        );
+
+        if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
+            let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+                def_id,
+                UserSubsts { substs, user_self_ty },
+            ));
+            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
+            self.write_user_type_annotation(hir_id, canonicalized);
+        }
+    }
+
+    pub fn write_user_type_annotation(
+        &self,
+        hir_id: hir::HirId,
+        canonical_user_type_annotation: CanonicalUserType<'tcx>,
+    ) {
+        debug!(
+            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
+            hir_id,
+            canonical_user_type_annotation,
+            self.tag(),
+        );
+
+        if !canonical_user_type_annotation.is_identity() {
+            self.typeck_results
+                .borrow_mut()
+                .user_provided_types_mut()
+                .insert(hir_id, canonical_user_type_annotation);
+        } else {
+            debug!("write_user_type_annotation: skipping identity substs");
+        }
+    }
+
+    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
+        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
+
+        if adj.is_empty() {
+            return;
+        }
+
+        let autoborrow_mut = adj.iter().any(|adj| {
+            matches!(adj, &Adjustment {
+                kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
+                ..
+            })
+        });
+
+        match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
+            Entry::Vacant(entry) => {
+                entry.insert(adj);
+            }
+            Entry::Occupied(mut entry) => {
+                debug!(" - composing on top of {:?}", entry.get());
+                match (&entry.get()[..], &adj[..]) {
+                    // Applying any adjustment on top of a NeverToAny
+                    // is a valid NeverToAny adjustment, because it can't
+                    // be reached.
+                    (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
+                    (&[
+                        Adjustment { kind: Adjust::Deref(_), .. },
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+                    ], &[
+                        Adjustment { kind: Adjust::Deref(_), .. },
+                        .. // Any following adjustments are allowed.
+                    ]) => {
+                        // A reborrow has no effect before a dereference.
+                    }
+                    // FIXME: currently we never try to compose autoderefs
+                    // and ReifyFnPointer/UnsafeFnPointer, but we could.
+                    _ =>
+                        bug!("while adjusting {:?}, can't compose {:?} and {:?}",
+                             expr, entry.get(), adj)
+                };
+                *entry.get_mut() = adj;
+            }
+        }
+
+        // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
+        // In this case implicit use of `Deref` and `Index` within `<expr>` should
+        // instead be `DerefMut` and `IndexMut`, so fix those up.
+        if autoborrow_mut {
+            self.convert_place_derefs_to_mutable(expr);
+        }
+    }
+
+    /// Basically whenever we are converting from a type scheme into
+    /// the fn body space, we always want to normalize associated
+    /// types as well. This function combines the two.
+    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let value = value.subst(self.tcx, substs);
+        let result = self.normalize_associated_types_in(span, &value);
+        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result);
+        result
+    }
+
+    /// As `instantiate_type_scheme`, but for the bounds found in a
+    /// generic type scheme.
+    pub(in super::super) fn instantiate_bounds(
+        &self,
+        span: Span,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
+        let bounds = self.tcx.predicates_of(def_id);
+        let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
+        let result = bounds.instantiate(self.tcx, substs);
+        let result = self.normalize_associated_types_in(span, &result);
+        debug!(
+            "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
+            bounds, substs, result, spans,
+        );
+        (result, spans)
+    }
+
+    /// Replaces the opaque types from the given value with type variables,
+    /// and records the `OpaqueTypeMap` for later use during writeback. See
+    /// `InferCtxt::instantiate_opaque_types` for more details.
+    pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
+        &self,
+        parent_id: hir::HirId,
+        value: &T,
+        value_span: Span,
+    ) -> T {
+        let parent_def_id = self.tcx.hir().local_def_id(parent_id);
+        debug!(
+            "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
+            parent_def_id, value
+        );
+
+        let (value, opaque_type_map) =
+            self.register_infer_ok_obligations(self.instantiate_opaque_types(
+                parent_def_id,
+                self.body_id,
+                self.param_env,
+                value,
+                value_span,
+            ));
+
+        let mut opaque_types = self.opaque_types.borrow_mut();
+        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
+        for (ty, decl) in opaque_type_map {
+            let _ = opaque_types.insert(ty, decl);
+            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
+        }
+
+        value
+    }
+
+    pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
+    }
+
+    pub(in super::super) fn normalize_associated_types_in_as_infer_ok<T>(
+        &self,
+        span: Span,
+        value: &T,
+    ) -> InferOk<'tcx, T>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value)
+    }
+
+    pub fn require_type_meets(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+        def_id: DefId,
+    ) {
+        self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
+    }
+
+    pub fn require_type_is_sized(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        if !ty.references_error() {
+            let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+            self.require_type_meets(ty, span, code, lang_item);
+        }
+    }
+
+    pub fn require_type_is_sized_deferred(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        if !ty.references_error() {
+            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
+        }
+    }
+
+    pub fn register_bound(
+        &self,
+        ty: Ty<'tcx>,
+        def_id: DefId,
+        cause: traits::ObligationCause<'tcx>,
+    ) {
+        if !ty.references_error() {
+            self.fulfillment_cx.borrow_mut().register_bound(
+                self,
+                self.param_env,
+                ty,
+                def_id,
+                cause,
+            );
+        }
+    }
+
+    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
+        let t = AstConv::ast_ty_to_ty(self, ast_t);
+        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
+        t
+    }
+
+    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
+        let ty = self.to_ty(ast_ty);
+        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
+
+        if Self::can_contain_user_lifetime_bounds(ty) {
+            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
+            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
+            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
+        }
+
+        ty
+    }
+
+    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
+        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
+        let c = ty::Const::from_anon_const(self.tcx, const_def_id);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
+    pub fn const_arg_to_const(
+        &self,
+        ast_c: &hir::AnonConst,
+        param_def_id: DefId,
+    ) -> &'tcx ty::Const<'tcx> {
+        let const_def = ty::WithOptConstParam {
+            did: self.tcx.hir().local_def_id(ast_c.hir_id),
+            const_param_did: Some(param_def_id),
+        };
+        let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
+    // If the type given by the user has free regions, save it for later, since
+    // NLL would like to enforce those. Also pass in types that involve
+    // projections, since those can resolve to `'static` bounds (modulo #54940,
+    // which hopefully will be fixed by the time you see this comment, dear
+    // reader, although I have my doubts). Also pass in types with inference
+    // types, because they may be repeated. Other sorts of things are already
+    // sufficiently enforced with erased regions. =)
+    fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        t.has_free_regions() || t.has_projections() || t.has_infer_types()
+    }
+
+    pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
+        match self.typeck_results.borrow().node_types().get(id) {
+            Some(&t) => t,
+            None if self.is_tainted_by_errors() => self.tcx.ty_error(),
+            None => {
+                bug!(
+                    "no type for node {}: {} in fcx {}",
+                    id,
+                    self.tcx.hir().node_to_string(id),
+                    self.tag()
+                );
+            }
+        }
+    }
+
+    /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
+    pub fn register_wf_obligation(
+        &self,
+        arg: subst::GenericArg<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        // WF obligations never themselves fail, so no real need to give a detailed cause:
+        let cause = traits::ObligationCause::new(span, self.body_id, code);
+        self.register_predicate(traits::Obligation::new(
+            cause,
+            self.param_env,
+            ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
+        ));
+    }
+
+    /// Registers obligations that all `substs` are well-formed.
+    pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
+        for arg in substs.iter().filter(|arg| {
+            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+        }) {
+            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
+        }
+    }
+
+    /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
+    /// type/region parameter was instantiated (`substs`), creates and registers suitable
+    /// trait/region obligations.
+    ///
+    /// For example, if there is a function:
+    ///
+    /// ```
+    /// fn foo<'a,T:'a>(...)
+    /// ```
+    ///
+    /// and a reference:
+    ///
+    /// ```
+    /// let f = foo;
+    /// ```
+    ///
+    /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
+    /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
+    pub fn add_obligations_for_parameters(
+        &self,
+        cause: traits::ObligationCause<'tcx>,
+        predicates: ty::InstantiatedPredicates<'tcx>,
+    ) {
+        assert!(!predicates.has_escaping_bound_vars());
+
+        debug!("add_obligations_for_parameters(predicates={:?})", predicates);
+
+        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
+            self.register_predicate(obligation);
+        }
+    }
+
+    // FIXME(arielb1): use this instead of field.ty everywhere
+    // Only for fields! Returns <none> for methods>
+    // Indifferent to privacy flags
+    pub fn field_ty(
+        &self,
+        span: Span,
+        field: &'tcx ty::FieldDef,
+        substs: SubstsRef<'tcx>,
+    ) -> Ty<'tcx> {
+        self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
+    }
+
+    pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
+        let mut generators = self.deferred_generator_interiors.borrow_mut();
+        for (body_id, interior, kind) in generators.drain(..) {
+            self.select_obligations_where_possible(false, |_| {});
+            crate::check::generator_interior::resolve_interior(
+                self, def_id, body_id, interior, kind,
+            );
+        }
+    }
+
+    // Tries to apply a fallback to `ty` if it is an unsolved variable.
+    //
+    // - Unconstrained ints are replaced with `i32`.
+    //
+    // - Unconstrained floats are replaced with with `f64`.
+    //
+    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
+    //   is enabled. Otherwise, they are replaced with `()`.
+    //
+    // Fallback becomes very dubious if we have encountered type-checking errors.
+    // In that case, fallback to Error.
+    // The return value indicates whether fallback has occurred.
+    pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
+        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
+        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
+
+        assert!(ty.is_ty_infer());
+        let fallback = match self.type_is_unconstrained_numeric(ty) {
+            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
+            UnconstrainedInt => self.tcx.types.i32,
+            UnconstrainedFloat => self.tcx.types.f64,
+            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
+            Neither => {
+                // This type variable was created from the instantiation of an opaque
+                // type. The fact that we're attempting to perform fallback for it
+                // means that the function neither constrained it to a concrete
+                // type, nor to the opaque type itself.
+                //
+                // For example, in this code:
+                //
+                //```
+                // type MyType = impl Copy;
+                // fn defining_use() -> MyType { true }
+                // fn other_use() -> MyType { defining_use() }
+                // ```
+                //
+                // `defining_use` will constrain the instantiated inference
+                // variable to `bool`, while `other_use` will constrain
+                // the instantiated inference variable to `MyType`.
+                //
+                // When we process opaque types during writeback, we
+                // will handle cases like `other_use`, and not count
+                // them as defining usages
+                //
+                // However, we also need to handle cases like this:
+                //
+                // ```rust
+                // pub type Foo = impl Copy;
+                // fn produce() -> Option<Foo> {
+                //     None
+                //  }
+                //  ```
+                //
+                // In the above snippet, the inference variable created by
+                // instantiating `Option<Foo>` will be completely unconstrained.
+                // We treat this as a non-defining use by making the inference
+                // variable fall back to the opaque type itself.
+                if let FallbackMode::All = mode {
+                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
+                        debug!(
+                            "fallback_if_possible: falling back opaque type var {:?} to {:?}",
+                            ty, opaque_ty
+                        );
+                        *opaque_ty
+                    } else {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            }
+        };
+        debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
+        self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
+        true
+    }
+
+    pub(in super::super) fn select_all_obligations_or_error(&self) {
+        debug!("select_all_obligations_or_error");
+        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
+            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
+        }
+    }
+
+    /// Select as many obligations as we can at present.
+    pub(in super::super) fn select_obligations_where_possible(
+        &self,
+        fallback_has_occurred: bool,
+        mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
+    ) {
+        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
+        if let Err(mut errors) = result {
+            mutate_fullfillment_errors(&mut errors);
+            self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+        }
+    }
+
+    /// For the overloaded place expressions (`*x`, `x[3]`), the trait
+    /// 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(in super::super) fn make_overloaded_place_return_type(
+        &self,
+        method: MethodCallee<'tcx>,
+    ) -> ty::TypeAndMut<'tcx> {
+        // extract method return type, which will be &T;
+        let ret_ty = method.sig.output();
+
+        // method returns &T, but the type as visible to user is T, so deref
+        ret_ty.builtin_deref(true).unwrap()
+    }
+
+    fn self_type_matches_expected_vid(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        expected_vid: ty::TyVid,
+    ) -> bool {
+        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
+        debug!(
+            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
+            trait_ref, self_ty, expected_vid
+        );
+        match *self_ty.kind() {
+            ty::Infer(ty::TyVar(found_vid)) => {
+                // FIXME: consider using `sub_root_var` here so we
+                // can see through subtyping.
+                let found_vid = self.root_var(found_vid);
+                debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
+                expected_vid == found_vid
+            }
+            _ => false,
+        }
+    }
+
+    pub(in super::super) fn obligations_for_self_ty<'b>(
+        &'b self,
+        self_ty: ty::TyVid,
+    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
+    + Captures<'tcx>
+    + 'b {
+        // FIXME: consider using `sub_root_var` here so we
+        // can see through subtyping.
+        let ty_var_root = self.root_var(self_ty);
+        debug!(
+            "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
+            self_ty,
+            ty_var_root,
+            self.fulfillment_cx.borrow().pending_obligations()
+        );
+
+        self.fulfillment_cx
+            .borrow()
+            .pending_obligations()
+            .into_iter()
+            .filter_map(move |obligation| {
+                match obligation.predicate.skip_binders() {
+                    ty::PredicateAtom::Projection(data) => {
+                        Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation))
+                    }
+                    ty::PredicateAtom::Trait(data, _) => {
+                        Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation))
+                    }
+                    ty::PredicateAtom::Subtype(..) => None,
+                    ty::PredicateAtom::RegionOutlives(..) => None,
+                    ty::PredicateAtom::TypeOutlives(..) => None,
+                    ty::PredicateAtom::WellFormed(..) => None,
+                    ty::PredicateAtom::ObjectSafe(..) => None,
+                    ty::PredicateAtom::ConstEvaluatable(..) => None,
+                    ty::PredicateAtom::ConstEquate(..) => None,
+                    // N.B., this predicate is created by breaking down a
+                    // `ClosureType: FnFoo()` predicate, where
+                    // `ClosureType` represents some `Closure`. It can't
+                    // possibly be referring to the current closure,
+                    // because we haven't produced the `Closure` for
+                    // this closure yet; this is exactly why the other
+                    // code is looking for a self type of a unresolved
+                    // inference variable.
+                    ty::PredicateAtom::ClosureKind(..) => None,
+                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+                }
+            })
+            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+    }
+
+    pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
+        self.obligations_for_self_ty(self_ty)
+            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
+    }
+
+    pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
+        vec![self.tcx.ty_error(); len]
+    }
+
+    /// Unifies the output type with the expected type early, for more coercions
+    /// and forward type information on the input expressions.
+    pub(in super::super) fn expected_inputs_for_expected_output(
+        &self,
+        call_span: Span,
+        expected_ret: Expectation<'tcx>,
+        formal_ret: Ty<'tcx>,
+        formal_args: &[Ty<'tcx>],
+    ) -> Vec<Ty<'tcx>> {
+        let formal_ret = self.resolve_vars_with_obligations(formal_ret);
+        let ret_ty = match expected_ret.only_has_type(self) {
+            Some(ret) => ret,
+            None => return Vec::new(),
+        };
+        let expect_args = self
+            .fudge_inference_if_ok(|| {
+                // Attempt to apply a subtyping relationship between the formal
+                // return type (likely containing type variables if the function
+                // is polymorphic) and the expected return type.
+                // No argument expectations are produced if unification fails.
+                let origin = self.misc(call_span);
+                let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
+
+                // FIXME(#27336) can't use ? here, Try::from_error doesn't default
+                // to identity so the resulting type is not constrained.
+                match ures {
+                    Ok(ok) => {
+                        // Process any obligations locally as much as
+                        // we can.  We don't care if some things turn
+                        // out unconstrained or ambiguous, as we're
+                        // just trying to get hints here.
+                        self.save_and_restore_in_snapshot_flag(|_| {
+                            let mut fulfill = TraitEngine::new(self.tcx);
+                            for obligation in ok.obligations {
+                                fulfill.register_predicate_obligation(self, obligation);
+                            }
+                            fulfill.select_where_possible(self)
+                        })
+                        .map_err(|_| ())?;
+                    }
+                    Err(_) => return Err(()),
+                }
+
+                // Record all the argument types, with the substitutions
+                // produced from the above subtyping unification.
+                Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect())
+            })
+            .unwrap_or_default();
+        debug!(
+            "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
+            formal_args, formal_ret, expect_args, expected_ret
+        );
+        expect_args
+    }
+
+    pub(in super::super) fn resolve_lang_item_path(
+        &self,
+        lang_item: hir::LangItem,
+        span: Span,
+        hir_id: hir::HirId,
+    ) -> (Res, Ty<'tcx>) {
+        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
+        let def_kind = self.tcx.def_kind(def_id);
+
+        let item_ty = if let DefKind::Variant = def_kind {
+            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
+        } else {
+            self.tcx.type_of(def_id)
+        };
+        let substs = self.infcx.fresh_substs_for_item(span, def_id);
+        let ty = item_ty.subst(self.tcx, substs);
+
+        self.write_resolution(hir_id, Ok((def_kind, def_id)));
+        self.add_required_obligations(span, def_id, &substs);
+        (Res::Def(def_kind, def_id), ty)
+    }
+
+    /// Resolves an associated value path into a base type and associated constant, or method
+    /// resolution. The newly resolved definition is written into `type_dependent_defs`.
+    pub fn resolve_ty_and_res_ufcs<'b>(
+        &self,
+        qpath: &'b QPath<'b>,
+        hir_id: hir::HirId,
+        span: Span,
+    ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
+        debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
+        let (ty, qself, item_segment) = match *qpath {
+            QPath::Resolved(ref opt_qself, ref path) => {
+                return (
+                    path.res,
+                    opt_qself.as_ref().map(|qself| self.to_ty(qself)),
+                    &path.segments[..],
+                );
+            }
+            QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
+            QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
+        };
+        if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
+        {
+            // 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(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err);
+            return (def, Some(ty), slice::from_ref(&**item_segment));
+        }
+        let item_name = item_segment.ident;
+        let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| {
+            let result = match error {
+                method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
+                _ => Err(ErrorReported),
+            };
+            if item_name.name != kw::Invalid {
+                if let Some(mut e) = self.report_method_error(
+                    span,
+                    ty,
+                    item_name,
+                    SelfSource::QPath(qself),
+                    error,
+                    None,
+                ) {
+                    e.emit();
+                }
+            }
+            result
+        });
+
+        // Write back the new resolution.
+        self.write_resolution(hir_id, result);
+        (
+            result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err),
+            Some(ty),
+            slice::from_ref(&**item_segment),
+        )
+    }
+
+    /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
+    pub(in super::super) fn get_node_fn_decl(
+        &self,
+        node: Node<'tcx>,
+    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
+        match node {
+            Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
+                // 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((&sig.decl, ident, ident.name != sym::main))
+            }
+            Node::TraitItem(&hir::TraitItem {
+                ident,
+                kind: hir::TraitItemKind::Fn(ref sig, ..),
+                ..
+            }) => Some((&sig.decl, ident, true)),
+            Node::ImplItem(&hir::ImplItem {
+                ident,
+                kind: hir::ImplItemKind::Fn(ref sig, ..),
+                ..
+            }) => Some((&sig.decl, ident, false)),
+            _ => None,
+        }
+    }
+
+    /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
+    /// suggestion can be made, `None` otherwise.
+    pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'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().get(blk_id);
+            self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+        })
+    }
+
+    pub(in super::super) fn note_internal_mutation_in_method(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if found != self.tcx.types.unit {
+            return;
+        }
+        if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
+            if self
+                .typeck_results
+                .borrow()
+                .expr_ty_adjusted_opt(rcvr)
+                .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
+            {
+                return;
+            }
+            let mut sp = MultiSpan::from_span(path_segment.ident.span);
+            sp.push_span_label(
+                path_segment.ident.span,
+                format!(
+                    "this call modifies {} in-place",
+                    match rcvr.kind {
+                        ExprKind::Path(QPath::Resolved(
+                            None,
+                            hir::Path { segments: [segment], .. },
+                        )) => format!("`{}`", segment.ident),
+                        _ => "its receiver".to_string(),
+                    }
+                ),
+            );
+            sp.push_span_label(
+                rcvr.span,
+                "you probably want to use this value after calling the method...".to_string(),
+            );
+            err.span_note(
+                sp,
+                &format!("method `{}` modifies its receiver in-place", path_segment.ident),
+            );
+            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+        }
+    }
+
+    pub(in super::super) fn note_need_for_fn_pointer(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
+            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                if sig1 != sig2 {
+                    return;
+                }
+                err.note(
+                    "different `fn` items always have unique types, even if their signatures are \
+                     the same",
+                );
+                (sig1, *did1, substs1)
+            }
+            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
+                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+                if sig1 != *sig2 {
+                    return;
+                }
+                (sig1, *did, substs)
+            }
+            _ => return,
+        };
+        err.help(&format!("change the expected type to be function pointer `{}`", sig));
+        err.help(&format!(
+            "if the expected type is due to type inference, cast the expected `fn` to a function \
+             pointer: `{} as {}`",
+            self.tcx.def_path_str_with_substs(did, substs),
+            sig
+        ));
+    }
+
+    pub(in super::super) fn could_remove_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> Option<Span> {
+        // Be helpful when the user wrote `{... expr;}` and
+        // taking the `;` off is enough to fix the error.
+        let last_stmt = blk.stmts.last()?;
+        let last_expr = match last_stmt.kind {
+            hir::StmtKind::Semi(ref e) => e,
+            _ => return None,
+        };
+        let last_expr_ty = self.node_ty(last_expr.hir_id);
+        if matches!(last_expr_ty.kind(), ty::Error(_))
+            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
+        {
+            return None;
+        }
+        let original_span = original_sp(last_stmt.span, blk.span);
+        Some(original_span.with_lo(original_span.hi() - BytePos(1)))
+    }
+
+    // Instantiates the given path, which must refer to an item with the given
+    // number of type parameters and type.
+    pub fn instantiate_value_path(
+        &self,
+        segments: &[hir::PathSegment<'_>],
+        self_ty: Option<Ty<'tcx>>,
+        res: Res,
+        span: Span,
+        hir_id: hir::HirId,
+    ) -> (Ty<'tcx>, Res) {
+        debug!(
+            "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})",
+            segments, self_ty, res, hir_id,
+        );
+
+        let tcx = self.tcx;
+
+        let path_segs = match res {
+            Res::Local(_) | Res::SelfCtor(_) => vec![],
+            Res::Def(kind, def_id) => {
+                AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id)
+            }
+            _ => bug!("instantiate_value_path on {:?}", res),
+        };
+
+        let mut user_self_ty = None;
+        let mut is_alias_variant_ctor = false;
+        match res {
+            Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
+                if let Some(self_ty) = self_ty {
+                    let adt_def = self_ty.ty_adt_def().unwrap();
+                    user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
+                    is_alias_variant_ctor = true;
+                }
+            }
+            Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
+                let container = tcx.associated_item(def_id).container;
+                debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
+                match container {
+                    ty::TraitContainer(trait_did) => {
+                        callee::check_legal_trait_for_method_call(tcx, span, None, trait_did)
+                    }
+                    ty::ImplContainer(impl_def_id) => {
+                        if segments.len() == 1 {
+                            // `<T>::assoc` will end up here, and so
+                            // can `T::assoc`. It this came from an
+                            // inherent impl, we need to record the
+                            // `T` for posterity (see `UserSelfTy` for
+                            // details).
+                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
+                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        // Now that we have categorized what space the parameters for each
+        // segment belong to, let's sort out the parameters that the user
+        // provided (if any) into their appropriate spaces. We'll also report
+        // errors if type parameters are provided in an inappropriate place.
+
+        let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
+        let generics_has_err = AstConv::prohibit_generics(
+            self,
+            segments.iter().enumerate().filter_map(|(index, seg)| {
+                if !generic_segs.contains(&index) || is_alias_variant_ctor {
+                    Some(seg)
+                } else {
+                    None
+                }
+            }),
+        );
+
+        if let Res::Local(hid) = res {
+            let ty = self.local_ty(span, hid).decl_ty;
+            let ty = self.normalize_associated_types_in(span, &ty);
+            self.write_ty(hir_id, ty);
+            return (ty, res);
+        }
+
+        if generics_has_err {
+            // Don't try to infer type parameters when prohibited generic arguments were given.
+            user_self_ty = None;
+        }
+
+        // Now we have to compare the types that the user *actually*
+        // provided against the types that were *expected*. If the user
+        // did not provide any types, then we want to substitute inference
+        // variables. If the user provided some types, we may still need
+        // to add defaults. If the user provided *too many* types, that's
+        // a problem.
+
+        let mut infer_args_for_err = FxHashSet::default();
+        for &PathSeg(def_id, index) in &path_segs {
+            let seg = &segments[index];
+            let generics = tcx.generics_of(def_id);
+            // Argument-position `impl Trait` is treated as a normal generic
+            // parameter internally, but we don't allow users to specify the
+            // parameter's value explicitly, so we have to do some error-
+            // checking here.
+            if let GenericArgCountResult {
+                correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }),
+                ..
+            } = AstConv::check_generic_arg_count_for_call(
+                tcx, span, &generics, &seg, false, // `is_method_call`
+            ) {
+                infer_args_for_err.insert(index);
+                self.set_tainted_by_errors(); // See issue #53251.
+            }
+        }
+
+        let has_self = path_segs
+            .last()
+            .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
+            .unwrap_or(false);
+
+        let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
+            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
+            match *ty.kind() {
+                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
+                    let variant = adt_def.non_enum_variant();
+                    let ctor_def_id = variant.ctor_def_id.unwrap();
+                    (
+                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
+                        Some(substs),
+                    )
+                }
+                _ => {
+                    let mut err = tcx.sess.struct_span_err(
+                        span,
+                        "the `Self` constructor can only be used with tuple or unit structs",
+                    );
+                    if let Some(adt_def) = ty.ty_adt_def() {
+                        match adt_def.adt_kind() {
+                            AdtKind::Enum => {
+                                err.help("did you mean to use one of the enum's variants?");
+                            }
+                            AdtKind::Struct | AdtKind::Union => {
+                                err.span_suggestion(
+                                    span,
+                                    "use curly brackets",
+                                    String::from("Self { /* fields */ }"),
+                                    Applicability::HasPlaceholders,
+                                );
+                            }
+                        }
+                    }
+                    err.emit();
+
+                    return (tcx.ty_error(), res);
+                }
+            }
+        } else {
+            (res, None)
+        };
+        let def_id = res.def_id();
+
+        // The things we are substituting into the type should not contain
+        // escaping late-bound regions, and nor should the base type scheme.
+        let ty = tcx.type_of(def_id);
+
+        let arg_count = GenericArgCountResult {
+            explicit_late_bound: ExplicitLateBound::No,
+            correct: if infer_args_for_err.is_empty() {
+                Ok(())
+            } else {
+                Err(GenericArgCountMismatch::default())
+            },
+        };
+
+        let substs = self_ctor_substs.unwrap_or_else(|| {
+            AstConv::create_substs_for_generic_args(
+                tcx,
+                def_id,
+                &[][..],
+                has_self,
+                self_ty,
+                arg_count,
+                // Provide the generic args, and whether types should be inferred.
+                |def_id| {
+                    if let Some(&PathSeg(_, index)) =
+                        path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
+                    {
+                        // If we've encountered an `impl Trait`-related error, we're just
+                        // going to infer the arguments for better error messages.
+                        if !infer_args_for_err.contains(&index) {
+                            // Check whether the user has provided generic arguments.
+                            if let Some(ref data) = segments[index].args {
+                                return (Some(data), segments[index].infer_args);
+                            }
+                        }
+                        return (None, segments[index].infer_args);
+                    }
+
+                    (None, true)
+                },
+                // Provide substitutions for parameters for which (valid) arguments have been provided.
+                |param, arg| match (&param.kind, arg) {
+                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
+                        AstConv::ast_region_to_region(self, lt, Some(param)).into()
+                    }
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
+                        self.to_ty(ty).into()
+                    }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        self.const_arg_to_const(&ct.value, param.def_id).into()
+                    }
+                    _ => unreachable!(),
+                },
+                // Provide substitutions for parameters for which arguments are inferred.
+                |substs, param, infer_args| {
+                    match param.kind {
+                        GenericParamDefKind::Lifetime => {
+                            self.re_infer(Some(param), span).unwrap().into()
+                        }
+                        GenericParamDefKind::Type { has_default, .. } => {
+                            if !infer_args && has_default {
+                                // If we have a default, then we it doesn't matter that we're not
+                                // inferring the type arguments: we provide the default where any
+                                // is missing.
+                                let default = tcx.type_of(param.def_id);
+                                self.normalize_ty(
+                                    span,
+                                    default.subst_spanned(tcx, substs.unwrap(), Some(span)),
+                                )
+                                .into()
+                            } else {
+                                // If no type arguments were provided, we have to infer them.
+                                // This case also occurs as a result of some malformed input, e.g.
+                                // a lifetime argument being given instead of a type parameter.
+                                // Using inference instead of `Error` gives better error messages.
+                                self.var_for_def(span, param)
+                            }
+                        }
+                        GenericParamDefKind::Const => {
+                            // FIXME(const_generics:defaults)
+                            // No const parameters were provided, we have to infer them.
+                            self.var_for_def(span, param)
+                        }
+                    }
+                },
+            )
+        });
+        assert!(!substs.has_escaping_bound_vars());
+        assert!(!ty.has_escaping_bound_vars());
+
+        // First, store the "user substs" for later.
+        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
+
+        self.add_required_obligations(span, def_id, &substs);
+
+        // Substitute the values for the type parameters into the type of
+        // the referenced item.
+        let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
+
+        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
+            // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
+            // is inherent, there is no `Self` parameter; instead, the impl needs
+            // type parameters, which we can infer by unifying the provided `Self`
+            // with the substituted impl type.
+            // This also occurs for an enum variant on a type alias.
+            let ty = tcx.type_of(impl_def_id);
+
+            let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
+            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
+                Ok(ok) => self.register_infer_ok_obligations(ok),
+                Err(_) => {
+                    self.tcx.sess.delay_span_bug(
+                        span,
+                        &format!(
+                        "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
+                        self_ty,
+                        impl_ty,
+                    ),
+                    );
+                }
+            }
+        }
+
+        self.check_rustc_args_require_const(def_id, hir_id, span);
+
+        debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
+        self.write_substs(hir_id, substs);
+
+        (ty_substituted, res)
+    }
+
+    /// Add all the obligations that are required, substituting and normalized appropriately.
+    fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+        let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
+
+        for (i, mut obligation) in traits::predicates_for_generics(
+            traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
+            self.param_env,
+            bounds,
+        )
+        .enumerate()
+        {
+            // This makes the error point at the bound, but we want to point at the argument
+            if let Some(span) = spans.get(i) {
+                obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
+            }
+            self.register_predicate(obligation);
+        }
+    }
+
+    /// Resolves `typ` by a single level if `typ` is a type variable.
+    /// If no resolution is possible, then an error is reported.
+    /// Numeric inference variables may be left unresolved.
+    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.resolve_vars_with_obligations(ty);
+        if !ty.is_ty_var() {
+            ty
+        } else {
+            if !self.is_tainted_by_errors() {
+                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
+                    .note("type must be known at this point")
+                    .emit();
+            }
+            let err = self.tcx.ty_error();
+            self.demand_suptype(sp, err, ty);
+            err
+        }
+    }
+
+    pub(in super::super) fn with_breakable_ctxt<F: FnOnce() -> R, R>(
+        &self,
+        id: hir::HirId,
+        ctxt: BreakableCtxt<'tcx>,
+        f: F,
+    ) -> (BreakableCtxt<'tcx>, R) {
+        let index;
+        {
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            index = enclosing_breakables.stack.len();
+            enclosing_breakables.by_id.insert(id, index);
+            enclosing_breakables.stack.push(ctxt);
+        }
+        let result = f();
+        let ctxt = {
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            debug_assert!(enclosing_breakables.stack.len() == index + 1);
+            enclosing_breakables.by_id.remove(&id).expect("missing breakable context");
+            enclosing_breakables.stack.pop().expect("missing breakable context")
+        };
+        (ctxt, result)
+    }
+
+    /// Instantiate a QueryResponse in a probe context, without a
+    /// good ObligationCause.
+    pub(in super::super) fn probe_instantiate_query_response(
+        &self,
+        span: Span,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    ) -> InferResult<'tcx, Ty<'tcx>> {
+        self.instantiate_query_response_and_region_obligations(
+            &traits::ObligationCause::misc(span, self.body_id),
+            self.param_env,
+            original_values,
+            query_result,
+        )
+    }
+
+    /// Returns `true` if an expression is contained inside the LHS of an assignment expression.
+    pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
+        let mut contained_in_place = false;
+
+        while let hir::Node::Expr(parent_expr) =
+            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
+        {
+            match &parent_expr.kind {
+                hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
+                    if lhs.hir_id == expr_id {
+                        contained_in_place = true;
+                        break;
+                    }
+                }
+                _ => (),
+            }
+            expr_id = parent_expr.hir_id;
+        }
+
+        contained_in_place
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
new file mode 100644
index 0000000..fd2f5eb
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -0,0 +1,996 @@
+use crate::astconv::AstConv;
+use crate::check::coercion::CoerceMany;
+use crate::check::method::MethodCallee;
+use crate::check::Expectation::*;
+use crate::check::TupleArgumentsFlag::*;
+use crate::check::{
+    potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
+    LocalTy, Needs, TupleArgumentsFlag,
+};
+
+use rustc_ast as ast;
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{ExprKind, Node, QPath};
+use rustc_middle::ty::adjustment::AllowTwoPhase;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, Ty};
+use rustc_session::Session;
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{self, MultiSpan, Span};
+use rustc_trait_selection::traits::{self, ObligationCauseCode};
+
+use std::mem::replace;
+use std::slice;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub(in super::super) fn check_casts(&self) {
+        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+        for cast in deferred_cast_checks.drain(..) {
+            cast.check(self);
+        }
+    }
+
+    pub(in super::super) fn check_method_argument_types(
+        &self,
+        sp: Span,
+        expr: &'tcx hir::Expr<'tcx>,
+        method: Result<MethodCallee<'tcx>, ()>,
+        args_no_rcvr: &'tcx [hir::Expr<'tcx>],
+        tuple_arguments: TupleArgumentsFlag,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let has_error = match method {
+            Ok(method) => method.substs.references_error() || method.sig.references_error(),
+            Err(_) => true,
+        };
+        if has_error {
+            let err_inputs = self.err_args(args_no_rcvr.len());
+
+            let err_inputs = match tuple_arguments {
+                DontTupleArguments => err_inputs,
+                TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
+            };
+
+            self.check_argument_types(
+                sp,
+                expr,
+                &err_inputs[..],
+                &[],
+                args_no_rcvr,
+                false,
+                tuple_arguments,
+                None,
+            );
+            return self.tcx.ty_error();
+        }
+
+        let method = method.unwrap();
+        // HACK(eddyb) ignore self in the definition (see above).
+        let expected_arg_tys = self.expected_inputs_for_expected_output(
+            sp,
+            expected,
+            method.sig.output(),
+            &method.sig.inputs()[1..],
+        );
+        self.check_argument_types(
+            sp,
+            expr,
+            &method.sig.inputs()[1..],
+            &expected_arg_tys[..],
+            args_no_rcvr,
+            method.sig.c_variadic,
+            tuple_arguments,
+            Some(method.def_id),
+        );
+        method.sig.output()
+    }
+
+    /// Generic function that factors out common logic from function calls,
+    /// method calls and overloaded operators.
+    pub(in super::super) fn check_argument_types(
+        &self,
+        sp: Span,
+        expr: &'tcx hir::Expr<'tcx>,
+        fn_inputs: &[Ty<'tcx>],
+        expected_arg_tys: &[Ty<'tcx>],
+        args: &'tcx [hir::Expr<'tcx>],
+        c_variadic: bool,
+        tuple_arguments: TupleArgumentsFlag,
+        def_id: Option<DefId>,
+    ) {
+        let tcx = self.tcx;
+        // Grab the argument types, supplying fresh type variables
+        // if the wrong number of arguments were supplied
+        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
+
+        // 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 fn_inputs.iter().zip(args.iter()) {
+            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
+        }
+
+        let expected_arg_count = fn_inputs.len();
+
+        let param_count_error = |expected_count: usize,
+                                 arg_count: usize,
+                                 error_code: &str,
+                                 c_variadic: bool,
+                                 sugg_unit: bool| {
+            let (span, start_span, args) = match &expr.kind {
+                hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
+                hir::ExprKind::MethodCall(path_segment, span, args, _) => (
+                    *span,
+                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
+                    path_segment
+                        .args
+                        .and_then(|args| args.args.iter().last())
+                        // Account for `foo.bar::<T>()`.
+                        .map(|arg| {
+                            // Skip the closing `>`.
+                            tcx.sess
+                                .source_map()
+                                .next_point(tcx.sess.source_map().next_point(arg.span()))
+                        })
+                        .unwrap_or(*span),
+                    &args[1..], // Skip the receiver.
+                ),
+                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
+            };
+            let arg_spans = if args.is_empty() {
+                // foo()
+                // ^^^-- supplied 0 arguments
+                // |
+                // expected 2 arguments
+                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
+            } else {
+                // foo(1, 2, 3)
+                // ^^^ -  -  - supplied 3 arguments
+                // |
+                // expected 2 arguments
+                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
+            };
+
+            let mut err = tcx.sess.struct_span_err_with_code(
+                span,
+                &format!(
+                    "this function takes {}{} but {} {} supplied",
+                    if c_variadic { "at least " } else { "" },
+                    potentially_plural_count(expected_count, "argument"),
+                    potentially_plural_count(arg_count, "argument"),
+                    if arg_count == 1 { "was" } else { "were" }
+                ),
+                DiagnosticId::Error(error_code.to_owned()),
+            );
+            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
+            for (i, span) in arg_spans.into_iter().enumerate() {
+                err.span_label(
+                    span,
+                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
+                );
+            }
+
+            if let Some(def_id) = def_id {
+                if let Some(node) = tcx.hir().get_if_local(def_id) {
+                    let mut spans: MultiSpan = node
+                        .ident()
+                        .map(|ident| ident.span)
+                        .unwrap_or_else(|| tcx.hir().span(node.hir_id().unwrap()))
+                        .into();
+
+                    if let Some(id) = node.body_id() {
+                        let body = tcx.hir().body(id);
+                        for param in body.params {
+                            spans.push_span_label(param.span, String::new());
+                        }
+                    }
+
+                    let def_kind = tcx.def_kind(def_id);
+                    err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+                }
+            }
+
+            if sugg_unit {
+                let sugg_span = tcx.sess.source_map().end_point(expr.span);
+                // remove closing `)` from the span
+                let sugg_span = sugg_span.shrink_to_lo();
+                err.span_suggestion(
+                    sugg_span,
+                    "expected the unit value `()`; create it with empty parentheses",
+                    String::from("()"),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                err.span_label(
+                    span,
+                    format!(
+                        "expected {}{}",
+                        if c_variadic { "at least " } else { "" },
+                        potentially_plural_count(expected_count, "argument")
+                    ),
+                );
+            }
+            err.emit();
+        };
+
+        let mut expected_arg_tys = expected_arg_tys.to_vec();
+
+        let formal_tys = if tuple_arguments == TupleArguments {
+            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+            match tuple_type.kind() {
+                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
+                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
+                    expected_arg_tys = vec![];
+                    self.err_args(args.len())
+                }
+                ty::Tuple(arg_types) => {
+                    expected_arg_tys = match expected_arg_tys.get(0) {
+                        Some(&ty) => match ty.kind() {
+                            ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
+                            _ => vec![],
+                        },
+                        None => vec![],
+                    };
+                    arg_types.iter().map(|k| k.expect_ty()).collect()
+                }
+                _ => {
+                    struct_span_err!(
+                        tcx.sess,
+                        sp,
+                        E0059,
+                        "cannot use call notation; the first type parameter \
+                         for the function trait is neither a tuple nor unit"
+                    )
+                    .emit();
+                    expected_arg_tys = vec![];
+                    self.err_args(args.len())
+                }
+            }
+        } else if expected_arg_count == supplied_arg_count {
+            fn_inputs.to_vec()
+        } else if c_variadic {
+            if supplied_arg_count >= expected_arg_count {
+                fn_inputs.to_vec()
+            } else {
+                param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
+                expected_arg_tys = vec![];
+                self.err_args(supplied_arg_count)
+            }
+        } else {
+            // is the missing argument of type `()`?
+            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit()
+            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(&fn_inputs[0]).is_unit()
+            } else {
+                false
+            };
+            param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
+
+            expected_arg_tys = vec![];
+            self.err_args(supplied_arg_count)
+        };
+
+        debug!(
+            "check_argument_types: formal_tys={:?}",
+            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
+        );
+
+        // If there is no expectation, expect formal_tys.
+        let expected_arg_tys =
+            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
+
+        let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
+
+        // Check the arguments.
+        // We do this in a pretty awful way: first we type-check any arguments
+        // that are not closures, then we type-check the closures. This is so
+        // that we have more information about the types of arguments when we
+        // type-check the functions. This isn't really the right way to do this.
+        for &check_closures in &[false, true] {
+            debug!("check_closures={}", check_closures);
+
+            // More awful hacks: before we check argument types, try to do
+            // an "opportunistic" trait resolution of any trait bounds on
+            // the call. This helps coercions.
+            if check_closures {
+                self.select_obligations_where_possible(false, |errors| {
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+                    self.point_at_arg_instead_of_call_if_possible(
+                        errors,
+                        &final_arg_types[..],
+                        sp,
+                        &args,
+                    );
+                })
+            }
+
+            // For C-variadic functions, we don't have a declared type for all of
+            // the arguments hence we only do our usual type checking with
+            // the arguments who's types we do know.
+            let t = if c_variadic {
+                expected_arg_count
+            } else if tuple_arguments == TupleArguments {
+                args.len()
+            } else {
+                supplied_arg_count
+            };
+            for (i, arg) in args.iter().take(t).enumerate() {
+                // Warn only for the first loop (the "no closures" one).
+                // Closure arguments themselves can't be diverging, but
+                // a previous argument can, e.g., `foo(panic!(), || {})`.
+                if !check_closures {
+                    self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
+                }
+
+                let is_closure = match arg.kind {
+                    ExprKind::Closure(..) => true,
+                    _ => false,
+                };
+
+                if is_closure != check_closures {
+                    continue;
+                }
+
+                debug!("checking the argument");
+                let formal_ty = formal_tys[i];
+
+                // The special-cased logic below has three functions:
+                // 1. Provide as good of an expected type as possible.
+                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
+
+                let checked_ty = self.check_expr_with_expectation(&arg, expected);
+
+                // 2. Coerce to the most detailed type that could be coerced
+                //    to, which is `expected_ty` if `rvalue_hint` returns an
+                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
+                // We're processing function arguments so we definitely want to use
+                // two-phase borrows.
+                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
+                final_arg_types.push((i, checked_ty, coerce_ty));
+
+                // 3. Relate the expected type and the formal one,
+                //    if the expected type was used for the coercion.
+                self.demand_suptype(arg.span, formal_ty, coerce_ty);
+            }
+        }
+
+        // We also need to make sure we at least write the ty of the other
+        // arguments which we skipped above.
+        if c_variadic {
+            fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
+                use crate::structured_errors::{StructuredDiagnostic, VariadicError};
+                VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
+            }
+
+            for arg in args.iter().skip(expected_arg_count) {
+                let arg_ty = self.check_expr(&arg);
+
+                // There are a few types which get autopromoted when passed via varargs
+                // in C but we just error out instead and require explicit casts.
+                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
+                match arg_ty.kind() {
+                    ty::Float(ast::FloatTy::F32) => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
+                    }
+                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
+                    }
+                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
+                    }
+                    ty::FnDef(..) => {
+                        let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
+                        let ptr_ty = self.resolve_vars_if_possible(&ptr_ty);
+                        variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+
+    // AST fragment checking
+    pub(in super::super) fn check_lit(
+        &self,
+        lit: &hir::Lit,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let tcx = self.tcx;
+
+        match lit.node {
+            ast::LitKind::Str(..) => tcx.mk_static_str(),
+            ast::LitKind::ByteStr(ref v) => {
+                tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
+            }
+            ast::LitKind::Byte(_) => tcx.types.u8,
+            ast::LitKind::Char(_) => tcx.types.char,
+            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
+                    ty::Int(_) | ty::Uint(_) => Some(ty),
+                    ty::Char => Some(tcx.types.u8),
+                    ty::RawPtr(..) => Some(tcx.types.usize),
+                    ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize),
+                    _ => None,
+                });
+                opt_ty.unwrap_or_else(|| self.next_int_var())
+            }
+            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
+            ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
+                    ty::Float(_) => Some(ty),
+                    _ => None,
+                });
+                opt_ty.unwrap_or_else(|| self.next_float_var())
+            }
+            ast::LitKind::Bool(_) => tcx.types.bool,
+            ast::LitKind::Err(_) => tcx.ty_error(),
+        }
+    }
+
+    pub fn check_struct_path(
+        &self,
+        qpath: &QPath<'_>,
+        hir_id: hir::HirId,
+    ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
+        let path_span = qpath.qself_span();
+        let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
+        let variant = match def {
+            Res::Err => {
+                self.set_tainted_by_errors();
+                return None;
+            }
+            Res::Def(DefKind::Variant, _) => match ty.kind() {
+                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
+                _ => bug!("unexpected type: {:?}", ty),
+            },
+            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            | Res::SelfTy(..) => match ty.kind() {
+                ty::Adt(adt, substs) if !adt.is_enum() => {
+                    Some((adt.non_enum_variant(), adt.did, substs))
+                }
+                _ => None,
+            },
+            _ => bug!("unexpected definition: {:?}", def),
+        };
+
+        if let Some((variant, did, substs)) = variant {
+            debug!("check_struct_path: did={:?} substs={:?}", did, substs);
+            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
+
+            // Check bounds on type arguments used in the path.
+            let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
+            let cause =
+                traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
+            self.add_obligations_for_parameters(cause, bounds);
+
+            Some((variant, ty))
+        } else {
+            struct_span_err!(
+                self.tcx.sess,
+                path_span,
+                E0071,
+                "expected struct, variant or union type, found {}",
+                ty.sort_string(self.tcx)
+            )
+            .span_label(path_span, "not a struct")
+            .emit();
+            None
+        }
+    }
+
+    pub fn check_decl_initializer(
+        &self,
+        local: &'tcx hir::Local<'tcx>,
+        init: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed
+        // for #42640 (default match binding modes).
+        //
+        // See #44848.
+        let ref_bindings = local.pat.contains_explicit_ref_binding();
+
+        let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty;
+        if let Some(m) = ref_bindings {
+            // Somewhat subtle: if we have a `ref` binding in the pattern,
+            // we want to avoid introducing coercions for the RHS. This is
+            // both because it helps preserve sanity and, in the case of
+            // ref mut, for soundness (issue #23116). In particular, in
+            // the latter case, we need to be clear that the type of the
+            // referent for the reference that results is *equal to* the
+            // type of the place it is referencing, and not some
+            // supertype thereof.
+            let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
+            self.demand_eqtype(init.span, local_ty, init_ty);
+            init_ty
+        } else {
+            self.check_expr_coercable_to_type(init, local_ty, None)
+        }
+    }
+
+    /// Type check a `let` statement.
+    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
+        // Determine and write the type which we'll check the pattern against.
+        let ty = self.local_ty(local.span, local.hir_id).decl_ty;
+        self.write_ty(local.hir_id, ty);
+
+        // Type check the initializer.
+        if let Some(ref init) = local.init {
+            let init_ty = self.check_decl_initializer(local, &init);
+            self.overwrite_local_ty_if_err(local, ty, init_ty);
+        }
+
+        // Does the expected pattern type originate from an expression and what is the span?
+        let (origin_expr, ty_span) = match (local.ty, local.init) {
+            (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
+            (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
+            _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
+        };
+
+        // Type check the pattern. Override if necessary to avoid knock-on errors.
+        self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
+        let pat_ty = self.node_ty(local.pat.hir_id);
+        self.overwrite_local_ty_if_err(local, ty, pat_ty);
+    }
+
+    pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
+        // Don't do all the complex logic below for `DeclItem`.
+        match stmt.kind {
+            hir::StmtKind::Item(..) => return,
+            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
+        }
+
+        self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
+
+        // Hide the outer diverging and `has_errors` flags.
+        let old_diverges = self.diverges.replace(Diverges::Maybe);
+        let old_has_errors = self.has_errors.replace(false);
+
+        match stmt.kind {
+            hir::StmtKind::Local(ref l) => {
+                self.check_decl_local(&l);
+            }
+            // Ignore for now.
+            hir::StmtKind::Item(_) => {}
+            hir::StmtKind::Expr(ref expr) => {
+                // Check with expected type of `()`.
+                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
+                    self.suggest_semicolon_at_end(expr.span, err);
+                });
+            }
+            hir::StmtKind::Semi(ref expr) => {
+                self.check_expr(&expr);
+            }
+        }
+
+        // Combine the diverging and `has_error` flags.
+        self.diverges.set(self.diverges.get() | old_diverges);
+        self.has_errors.set(self.has_errors.get() | old_has_errors);
+    }
+
+    pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
+        let unit = self.tcx.mk_unit();
+        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
+
+        // if the block produces a `!` value, that can always be
+        // (effectively) coerced to unit.
+        if !ty.is_never() {
+            self.demand_suptype(blk.span, unit, ty);
+        }
+    }
+
+    pub(in super::super) fn check_block_with_expected(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let prev = {
+            let mut fcx_ps = self.ps.borrow_mut();
+            let unsafety_state = fcx_ps.recurse(blk);
+            replace(&mut *fcx_ps, unsafety_state)
+        };
+
+        // In some cases, blocks have just one exit, but other blocks
+        // can be targeted by multiple breaks. This can happen both
+        // with labeled blocks as well as when we desugar
+        // a `try { ... }` expression.
+        //
+        // Example 1:
+        //
+        //    'a: { if true { break 'a Err(()); } Ok(()) }
+        //
+        // Here we would wind up with two coercions, one from
+        // `Err(())` and the other from the tail expression
+        // `Ok(())`. If the tail expression is omitted, that's a
+        // "forced unit" -- unless the block diverges, in which
+        // case we can ignore the tail expression (e.g., `'a: {
+        // break 'a 22; }` would not force the type of the block
+        // to be `()`).
+        let tail_expr = blk.expr.as_ref();
+        let coerce_to_ty = expected.coercion_target_type(self, blk.span);
+        let coerce = if blk.targeted_by_break {
+            CoerceMany::new(coerce_to_ty)
+        } else {
+            let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
+                Some(e) => slice::from_ref(e),
+                None => &[],
+            };
+            CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
+        };
+
+        let prev_diverges = self.diverges.get();
+        let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
+
+        let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
+            for s in blk.stmts {
+                self.check_stmt(s);
+            }
+
+            // check the tail expression **without** holding the
+            // `enclosing_breakables` lock below.
+            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
+
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
+            let coerce = ctxt.coerce.as_mut().unwrap();
+            if let Some(tail_expr_ty) = tail_expr_ty {
+                let tail_expr = tail_expr.unwrap();
+                let span = self.get_expr_coercion_span(tail_expr);
+                let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
+                coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
+            } else {
+                // Subtle: if there is no explicit tail expression,
+                // that is typically equivalent to a tail expression
+                // of `()` -- except if the block diverges. In that
+                // case, there is no value supplied from the tail
+                // expression (assuming there are no other breaks,
+                // this implies that the type of the block will be
+                // `!`).
+                //
+                // #41425 -- label the implicit `()` as being the
+                // "found type" here, rather than the "expected type".
+                if !self.diverges.get().is_always() {
+                    // #50009 -- Do not point at the entire fn block span, point at the return type
+                    // span, as it is the cause of the requirement, and
+                    // `consider_hint_about_removing_semicolon` will point at the last expression
+                    // if it were a relevant part of the error. This improves usability in editors
+                    // 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) {
+                        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
+                            // output would otherwise be incorrect and even misleading. Make sure
+                            // the span we're aiming at correspond to a `fn` body.
+                            if block_sp == blk.span {
+                                sp = ret_sp;
+                                fn_span = Some(ident.span);
+                            }
+                        }
+                    }
+                    coerce.coerce_forced_unit(
+                        self,
+                        &self.misc(sp),
+                        &mut |err| {
+                            if let Some(expected_ty) = expected.only_has_type(self) {
+                                self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+                            }
+                            if let Some(fn_span) = fn_span {
+                                err.span_label(
+                                    fn_span,
+                                    "implicitly returns `()` as its body has no tail or `return` \
+                                     expression",
+                                );
+                            }
+                        },
+                        false,
+                    );
+                }
+            }
+        });
+
+        if ctxt.may_break {
+            // If we can break from the block, then the block's exit is always reachable
+            // (... as long as the entry is reachable) - regardless of the tail of the block.
+            self.diverges.set(prev_diverges);
+        }
+
+        let mut ty = ctxt.coerce.unwrap().complete(self);
+
+        if self.has_errors.get() || ty.references_error() {
+            ty = self.tcx.ty_error()
+        }
+
+        self.write_ty(blk.hir_id, ty);
+
+        *self.ps.borrow_mut() = prev;
+        ty
+    }
+
+    pub(in super::super) fn check_rustc_args_require_const(
+        &self,
+        def_id: DefId,
+        hir_id: hir::HirId,
+        span: Span,
+    ) {
+        // We're only interested in functions tagged with
+        // #[rustc_args_required_const], so ignore anything that's not.
+        if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
+            return;
+        }
+
+        // If our calling expression is indeed the function itself, we're good!
+        // If not, generate an error that this can only be called directly.
+        if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) {
+            if let ExprKind::Call(ref callee, ..) = expr.kind {
+                if callee.hir_id == hir_id {
+                    return;
+                }
+            }
+        }
+
+        self.tcx.sess.span_err(
+            span,
+            "this function can only be invoked directly, not through a function pointer",
+        );
+    }
+
+    /// A common error is to add an extra semicolon:
+    ///
+    /// ```
+    /// fn foo() -> usize {
+    ///     22;
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the final statement in a block is an
+    /// expression with an explicit semicolon whose type is compatible
+    /// with `expected_ty`. If so, it suggests removing the semicolon.
+    fn consider_hint_about_removing_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
+            err.span_suggestion(
+                span_semi,
+                "consider removing this semicolon",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
+        let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
+        match node {
+            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
+            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
+                let body = self.tcx.hir().body(body_id);
+                if let ExprKind::Block(block, _) = &body.value.kind {
+                    return Some(block.span);
+                }
+            }
+            _ => {}
+        }
+        None
+    }
+
+    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
+    fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
+        let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_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:
+    /// ```text
+    /// if false { return 0i32; } else { 1u32 }
+    /// //                               ^^^^ point at this instead of the whole `if` expression
+    /// ```
+    fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
+        if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
+            let arm_spans: Vec<Span> = arms
+                .iter()
+                .filter_map(|arm| {
+                    self.in_progress_typeck_results
+                        .and_then(|typeck_results| {
+                            typeck_results.borrow().node_type_opt(arm.body.hir_id)
+                        })
+                        .and_then(|arm_ty| {
+                            if arm_ty.is_never() {
+                                None
+                            } else {
+                                Some(match &arm.body.kind {
+                                    // Point at the tail expression when possible.
+                                    hir::ExprKind::Block(block, _) => {
+                                        block.expr.as_ref().map(|e| e.span).unwrap_or(block.span)
+                                    }
+                                    _ => arm.body.span,
+                                })
+                            }
+                        })
+                })
+                .collect();
+            if arm_spans.len() == 1 {
+                return arm_spans[0];
+            }
+        }
+        expr.span
+    }
+
+    fn overwrite_local_ty_if_err(
+        &self,
+        local: &'tcx hir::Local<'tcx>,
+        decl_ty: Ty<'tcx>,
+        ty: Ty<'tcx>,
+    ) {
+        if ty.references_error() {
+            // Override the types everywhere with `err()` to avoid knock on errors.
+            self.write_ty(local.hir_id, ty);
+            self.write_ty(local.pat.hir_id, ty);
+            let local_ty = LocalTy { decl_ty, revealed_ty: ty };
+            self.locals.borrow_mut().insert(local.hir_id, local_ty);
+            self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
+        }
+    }
+
+    // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
+    // The newly resolved definition is written into `type_dependent_defs`.
+    fn finish_resolving_struct_path(
+        &self,
+        qpath: &QPath<'_>,
+        path_span: Span,
+        hir_id: hir::HirId,
+    ) -> (Res, Ty<'tcx>) {
+        match *qpath {
+            QPath::Resolved(ref maybe_qself, ref path) => {
+                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
+                let ty = AstConv::res_to_ty(self, self_ty, path, true);
+                (path.res, ty)
+            }
+            QPath::TypeRelative(ref qself, ref segment) => {
+                let ty = self.to_ty(qself);
+
+                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
+                    path.res
+                } else {
+                    Res::Err
+                };
+                let result =
+                    AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
+                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
+                let result = result.map(|(_, kind, def_id)| (kind, def_id));
+
+                // Write back the new resolution.
+                self.write_resolution(hir_id, result);
+
+                (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
+            }
+            QPath::LangItem(lang_item, span) => {
+                self.resolve_lang_item_path(lang_item, span, hir_id)
+            }
+        }
+    }
+
+    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
+    /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
+    /// reference a type argument. The reason to walk also the checked type is that the coerced type
+    /// can be not easily comparable with predicate type (because of coercion). If the types match
+    /// for either checked or coerced type, and there's only *one* argument that does, we point at
+    /// the corresponding argument's expression span instead of the `fn` call path span.
+    fn point_at_arg_instead_of_call_if_possible(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
+        call_sp: Span,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) {
+        // We *do not* do this for desugared call spans to keep good diagnostics when involving
+        // the `?` operator.
+        if call_sp.desugaring_kind().is_some() {
+            return;
+        }
+
+        for error in errors {
+            // Only if the cause is somewhere inside the expression we want try to point at arg.
+            // Otherwise, it means that the cause is somewhere else and we should not change
+            // anything because we can break the correct span.
+            if !call_sp.contains(error.obligation.cause.span) {
+                continue;
+            }
+
+            if let ty::PredicateAtom::Trait(predicate, _) =
+                error.obligation.predicate.skip_binders()
+            {
+                // Collect the argument position for all arguments that could have caused this
+                // `FulfillmentError`.
+                let mut referenced_in = final_arg_types
+                    .iter()
+                    .map(|&(i, checked_ty, _)| (i, checked_ty))
+                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+                    .flat_map(|(i, ty)| {
+                        let ty = self.resolve_vars_if_possible(&ty);
+                        // We walk the argument type because the argument's type could have
+                        // been `Option<T>`, but the `FulfillmentError` references `T`.
+                        if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
+                            Some(i)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect::<Vec<usize>>();
+
+                // Both checked and coerced types could have matched, thus we need to remove
+                // duplicates.
+
+                // We sort primitive type usize here and can use unstable sort
+                referenced_in.sort_unstable();
+                referenced_in.dedup();
+
+                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+                    // We make sure that only *one* argument matches the obligation failure
+                    // and we assign the obligation's span to its expression's.
+                    error.obligation.cause.make_mut().span = args[ref_in].span;
+                    error.points_at_arg_span = true;
+                }
+            }
+        }
+    }
+
+    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
+    /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
+    /// were caused by them. If they were, we point at the corresponding type argument's span
+    /// instead of the `fn` call path span.
+    fn point_at_type_arg_instead_of_call_if_possible(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+    ) {
+        if let hir::ExprKind::Call(path, _) = &call_expr.kind {
+            if let hir::ExprKind::Path(qpath) = &path.kind {
+                if let hir::QPath::Resolved(_, path) = &qpath {
+                    for error in errors {
+                        if let ty::PredicateAtom::Trait(predicate, _) =
+                            error.obligation.predicate.skip_binders()
+                        {
+                            // If any of the type arguments in this path segment caused the
+                            // `FullfillmentError`, point at its span (#61860).
+                            for arg in path
+                                .segments
+                                .iter()
+                                .filter_map(|seg| seg.args.as_ref())
+                                .flat_map(|a| a.args.iter())
+                            {
+                                if let hir::GenericArg::Type(hir_ty) = &arg {
+                                    if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
+                                        &hir_ty.kind
+                                    {
+                                        // Avoid ICE with associated types. As this is best
+                                        // effort only, it's ok to ignore the case. It
+                                        // would trigger in `is_send::<T::AssocType>();`
+                                        // from `typeck-default-trait-impl-assoc-type.rs`.
+                                    } else {
+                                        let ty = AstConv::ast_ty_to_ty(self, hir_ty);
+                                        let ty = self.resolve_vars_if_possible(&ty);
+                                        if ty == predicate.self_ty() {
+                                            error.obligation.cause.make_mut().span = hir_ty.span;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
new file mode 100644
index 0000000..72c3b23
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -0,0 +1,295 @@
+mod _impl;
+mod checks;
+mod suggestions;
+
+pub use _impl::*;
+pub use checks::*;
+pub use suggestions::*;
+
+use crate::astconv::AstConv;
+use crate::check::coercion::DynamicCoerceMany;
+use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
+
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::hir::map::blocks::FnLikeNode;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
+use rustc_session::Session;
+use rustc_span::{self, Span};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
+
+use std::cell::{Cell, RefCell};
+use std::ops::Deref;
+
+pub struct FnCtxt<'a, 'tcx> {
+    pub(super) body_id: hir::HirId,
+
+    /// The parameter environment used for proving trait obligations
+    /// in this function. This can change when we descend into
+    /// closures (as they bring new things into scope), hence it is
+    /// not part of `Inherited` (as of the time of this writing,
+    /// closures do not yet change the environment, but they will
+    /// eventually).
+    pub(super) param_env: ty::ParamEnv<'tcx>,
+
+    /// Number of errors that had been reported when we started
+    /// checking this function. On exit, if we find that *more* errors
+    /// have been reported, we will skip regionck and other work that
+    /// expects the types within the function to be consistent.
+    // FIXME(matthewjasper) This should not exist, and it's not correct
+    // if type checking is run in parallel.
+    err_count_on_creation: usize,
+
+    /// If `Some`, this stores coercion information for returned
+    /// expressions. If `None`, this is in a context where return is
+    /// inappropriate, such as a const expression.
+    ///
+    /// This is a `RefCell<DynamicCoerceMany>`, which means that we
+    /// can track all the return expressions and then use them to
+    /// compute a useful coercion from the set, similar to a match
+    /// expression or other branching context. You can use methods
+    /// like `expected_ty` to access the declared return type (if
+    /// any).
+    pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
+
+    pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
+
+    pub(super) ret_type_span: Option<Span>,
+
+    /// Used exclusively to reduce cost of advanced evaluation used for
+    /// more helpful diagnostics.
+    pub(super) in_tail_expr: bool,
+
+    /// First span of a return site that we find. Used in error messages.
+    pub(super) ret_coercion_span: RefCell<Option<Span>>,
+
+    pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
+
+    pub(super) ps: RefCell<UnsafetyState>,
+
+    /// Whether the last checked node generates a divergence (e.g.,
+    /// `return` will set this to `Always`). In general, when entering
+    /// an expression or other node in the tree, the initial value
+    /// indicates whether prior parts of the containing expression may
+    /// have diverged. It is then typically set to `Maybe` (and the
+    /// old value remembered) for processing the subparts of the
+    /// current expression. As each subpart is processed, they may set
+    /// the flag to `Always`, etc. Finally, at the end, we take the
+    /// result and "union" it with the original value, so that when we
+    /// return the flag indicates if any subpart of the parent
+    /// expression (up to and including this part) has diverged. So,
+    /// if you read it after evaluating a subexpression `X`, the value
+    /// you get indicates whether any subexpression that was
+    /// evaluating up to and including `X` diverged.
+    ///
+    /// We currently use this flag only for diagnostic purposes:
+    ///
+    /// - To warn about unreachable code: if, after processing a
+    ///   sub-expression but before we have applied the effects of the
+    ///   current node, we see that the flag is set to `Always`, we
+    ///   can issue a warning. This corresponds to something like
+    ///   `foo(return)`; we warn on the `foo()` expression. (We then
+    ///   update the flag to `WarnedAlways` to suppress duplicate
+    ///   reports.) Similarly, if we traverse to a fresh statement (or
+    ///   tail expression) from a `Always` setting, we will issue a
+    ///   warning. This corresponds to something like `{return;
+    ///   foo();}` or `{return; 22}`, where we would warn on the
+    ///   `foo()` or `22`.
+    ///
+    /// An expression represents dead code if, after checking it,
+    /// the diverges flag is set to something other than `Maybe`.
+    pub(super) diverges: Cell<Diverges>,
+
+    /// Whether any child nodes have any type errors.
+    pub(super) has_errors: Cell<bool>,
+
+    pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
+
+    pub(super) inh: &'a Inherited<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn new(
+        inh: &'a Inherited<'a, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+    ) -> FnCtxt<'a, 'tcx> {
+        FnCtxt {
+            body_id,
+            param_env,
+            err_count_on_creation: inh.tcx.sess.err_count(),
+            ret_coercion: None,
+            ret_coercion_impl_trait: None,
+            ret_type_span: None,
+            in_tail_expr: false,
+            ret_coercion_span: RefCell::new(None),
+            resume_yield_tys: None,
+            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
+            diverges: Cell::new(Diverges::Maybe),
+            has_errors: Cell::new(false),
+            enclosing_breakables: RefCell::new(EnclosingBreakables {
+                stack: Vec::new(),
+                by_id: Default::default(),
+            }),
+            inh,
+        }
+    }
+
+    pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
+        ObligationCause::new(span, self.body_id, code)
+    }
+
+    pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
+        self.cause(span, ObligationCauseCode::MiscObligation)
+    }
+
+    pub fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+
+    pub fn errors_reported_since_creation(&self) -> bool {
+        self.tcx.sess.err_count() > self.err_count_on_creation
+    }
+}
+
+impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
+    type Target = Inherited<'a, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.inh
+    }
+}
+
+impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn item_def_id(&self) -> Option<DefId> {
+        None
+    }
+
+    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
+        // FIXME: refactor this into a method
+        let node = self.tcx.hir().get(self.body_id);
+        if let Some(fn_like) = FnLikeNode::from_node(node) {
+            fn_like.constness()
+        } else {
+            hir::Constness::NotConst
+        }
+    }
+
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
+        let tcx = self.tcx;
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        let item_id = tcx.hir().ty_param_owner(hir_id);
+        let item_def_id = tcx.hir().local_def_id(item_id);
+        let generics = tcx.generics_of(item_def_id);
+        let index = generics.param_def_id_to_index[&def_id];
+        ty::GenericPredicates {
+            parent: None,
+            predicates: tcx.arena.alloc_from_iter(
+                self.param_env.caller_bounds().iter().filter_map(|predicate| {
+                    match predicate.skip_binders() {
+                        ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
+                            // HACK(eddyb) should get the original `Span`.
+                            let span = tcx.def_span(def_id);
+                            Some((predicate, span))
+                        }
+                        _ => None,
+                    }
+                }),
+            ),
+        }
+    }
+
+    fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
+        let v = match def {
+            Some(def) => infer::EarlyBoundRegion(span, def.name),
+            None => infer::MiscVariable(span),
+        };
+        Some(self.next_region_var(v))
+    }
+
+    fn allow_ty_infer(&self) -> bool {
+        true
+    }
+
+    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+        if let Some(param) = param {
+            if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
+                return ty;
+            }
+            unreachable!()
+        } else {
+            self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::TypeInference,
+                span,
+            })
+        }
+    }
+
+    fn ct_infer(
+        &self,
+        ty: Ty<'tcx>,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx> {
+        if let Some(param) = param {
+            if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
+                return ct;
+            }
+            unreachable!()
+        } else {
+            self.next_const_var(
+                ty,
+                ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
+            )
+        }
+    }
+
+    fn projected_ty_from_poly_trait_ref(
+        &self,
+        span: Span,
+        item_def_id: DefId,
+        item_segment: &hir::PathSegment<'_>,
+        poly_trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Ty<'tcx> {
+        let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
+            span,
+            infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
+            &poly_trait_ref,
+        );
+
+        let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
+            self,
+            self.tcx,
+            span,
+            item_def_id,
+            item_segment,
+            trait_ref.substs,
+        );
+
+        self.tcx().mk_projection(item_def_id, item_substs)
+    }
+
+    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if ty.has_escaping_bound_vars() {
+            ty // FIXME: normalization and escaping regions
+        } else {
+            self.normalize_associated_types_in(span, &ty)
+        }
+    }
+
+    fn set_tainted_by_errors(&self) {
+        self.infcx.set_tainted_by_errors()
+    }
+
+    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
+        self.write_ty(hir_id, ty)
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
new file mode 100644
index 0000000..9bad02c
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -0,0 +1,528 @@
+use super::FnCtxt;
+use crate::astconv::AstConv;
+
+use rustc_ast::util::parser::ExprPrecedence;
+use rustc_span::{self, Span};
+use rustc_trait_selection::traits;
+
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ExprKind, ItemKind, Node};
+use rustc_infer::infer;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::symbol::kw;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
+
+use std::iter;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub(in super::super) fn suggest_semicolon_at_end(
+        &self,
+        span: Span,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        err.span_suggestion_short(
+            span.shrink_to_hi(),
+            "consider using a semicolon here",
+            ";".to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+
+    /// On implicit return expressions with mismatched types, provides the following suggestions:
+    ///
+    /// - Points out the method's return type as the reason for the expected type.
+    /// - Possible missing semicolon.
+    /// - Possible missing return type if the return type is the default, and not `fn main()`.
+    pub fn suggest_mismatched_types_on_tail(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &'tcx hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        cause_span: Span,
+        blk_id: hir::HirId,
+    ) -> bool {
+        let expr = expr.peel_drop_temps();
+        self.suggest_missing_semicolon(err, expr, expected, cause_span);
+        let mut pointing_at_return_type = false;
+        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+            pointing_at_return_type =
+                self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
+        }
+        pointing_at_return_type
+    }
+
+    /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
+    /// the ctor would successfully solve the type mismatch and if so, suggest it:
+    /// ```
+    /// fn foo(x: usize) -> usize { x }
+    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
+    /// ```
+    fn suggest_fn_call(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let hir = self.tcx.hir();
+        let (def_id, sig) = match *found.kind() {
+            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
+            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
+            _ => return false,
+        };
+
+        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0;
+        let sig = self.normalize_associated_types_in(expr.span, &sig);
+        if self.can_coerce(sig.output(), expected) {
+            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
+                (String::new(), Applicability::MachineApplicable)
+            } else {
+                ("...".to_string(), Applicability::HasPlaceholders)
+            };
+            let mut msg = "call this function";
+            match hir.get_if_local(def_id) {
+                Some(
+                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
+                    | Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(_, body_id), ..
+                    })
+                    | Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
+                        ..
+                    }),
+                ) => {
+                    let body = hir.body(*body_id);
+                    sugg_call = body
+                        .params
+                        .iter()
+                        .map(|param| match &param.pat.kind {
+                            hir::PatKind::Binding(_, _, ident, None)
+                                if ident.name != kw::SelfLower =>
+                            {
+                                ident.to_string()
+                            }
+                            _ => "_".to_string(),
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ");
+                }
+                Some(Node::Expr(hir::Expr {
+                    kind: ExprKind::Closure(_, _, body_id, _, _),
+                    span: full_closure_span,
+                    ..
+                })) => {
+                    if *full_closure_span == expr.span {
+                        return false;
+                    }
+                    msg = "call this closure";
+                    let body = hir.body(*body_id);
+                    sugg_call = body
+                        .params
+                        .iter()
+                        .map(|param| match &param.pat.kind {
+                            hir::PatKind::Binding(_, _, ident, None)
+                                if ident.name != kw::SelfLower =>
+                            {
+                                ident.to_string()
+                            }
+                            _ => "_".to_string(),
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ");
+                }
+                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
+                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
+                    match def_id.as_local().map(|def_id| hir.def_kind(def_id)) {
+                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
+                            msg = "instantiate this tuple variant";
+                        }
+                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
+                            msg = "instantiate this tuple struct";
+                        }
+                        _ => {}
+                    }
+                }
+                Some(Node::ForeignItem(hir::ForeignItem {
+                    kind: hir::ForeignItemKind::Fn(_, idents, _),
+                    ..
+                })) => {
+                    sugg_call = idents
+                        .iter()
+                        .map(|ident| {
+                            if ident.name != kw::SelfLower {
+                                ident.to_string()
+                            } else {
+                                "_".to_string()
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                }
+                Some(Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
+                    ..
+                })) => {
+                    sugg_call = idents
+                        .iter()
+                        .map(|ident| {
+                            if ident.name != kw::SelfLower {
+                                ident.to_string()
+                            } else {
+                                "_".to_string()
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                }
+                _ => {}
+            }
+            err.span_suggestion_verbose(
+                expr.span.shrink_to_hi(),
+                &format!("use parentheses to {}", msg),
+                format!("({})", sugg_call),
+                applicability,
+            );
+            return true;
+        }
+        false
+    }
+
+    pub fn suggest_deref_ref_or_into(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+    ) {
+        if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
+            err.span_suggestion(sp, msg, suggestion, applicability);
+        } else if let (ty::FnDef(def_id, ..), true) =
+            (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
+        {
+            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
+                let sp = self.sess().source_map().guess_head_span(sp);
+                err.span_label(sp, &format!("{} defined here", found));
+            }
+        } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+            let is_struct_pat_shorthand_field =
+                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
+            let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
+            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
+                let mut suggestions = iter::repeat(&expr_text)
+                    .zip(methods.iter())
+                    .filter_map(|(receiver, method)| {
+                        let method_call = format!(".{}()", method.ident);
+                        if receiver.ends_with(&method_call) {
+                            None // do not suggest code that is already there (#53348)
+                        } else {
+                            let method_call_list = [".to_vec()", ".to_string()"];
+                            let sugg = if receiver.ends_with(".clone()")
+                                && method_call_list.contains(&method_call.as_str())
+                            {
+                                let max_len = receiver.rfind('.').unwrap();
+                                format!("{}{}", &receiver[..max_len], method_call)
+                            } else {
+                                if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
+                                    format!("({}){}", receiver, method_call)
+                                } else {
+                                    format!("{}{}", receiver, method_call)
+                                }
+                            };
+                            Some(if is_struct_pat_shorthand_field {
+                                format!("{}: {}", receiver, sugg)
+                            } else {
+                                sugg
+                            })
+                        }
+                    })
+                    .peekable();
+                if suggestions.peek().is_some() {
+                    err.span_suggestions(
+                        expr.span,
+                        "try using a conversion method",
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+    }
+
+    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
+    /// in the heap by calling `Box::new()`.
+    pub(in super::super) fn suggest_boxing_when_appropriate(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
+            // Do not suggest `Box::new` in const context.
+            return;
+        }
+        if !expected.is_box() || found.is_box() {
+            return;
+        }
+        let boxed_found = self.tcx.mk_box(found);
+        if let (true, Ok(snippet)) = (
+            self.can_coerce(boxed_found, expected),
+            self.sess().source_map().span_to_snippet(expr.span),
+        ) {
+            err.span_suggestion(
+                expr.span,
+                "store this in the heap by calling `Box::new`",
+                format!("Box::new({})", snippet),
+                Applicability::MachineApplicable,
+            );
+            err.note(
+                "for more on the distinction between the stack and the heap, read \
+                 https://doc.rust-lang.org/book/ch15-01-box.html, \
+                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
+                 https://doc.rust-lang.org/std/boxed/index.html",
+            );
+        }
+    }
+
+    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
+    pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        // Handle #68197.
+
+        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
+            // Do not suggest `Box::new` in const context.
+            return false;
+        }
+        let pin_did = self.tcx.lang_items().pin_type();
+        match expected.kind() {
+            ty::Adt(def, _) if Some(def.did) != pin_did => return false,
+            // This guards the `unwrap` and `mk_box` below.
+            _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
+            _ => {}
+        }
+        let boxed_found = self.tcx.mk_box(found);
+        let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
+        if let (true, Ok(snippet)) = (
+            self.can_coerce(new_found, expected),
+            self.sess().source_map().span_to_snippet(expr.span),
+        ) {
+            match found.kind() {
+                ty::Adt(def, _) if def.is_box() => {
+                    err.help("use `Box::pin`");
+                }
+                _ => {
+                    err.span_suggestion(
+                        expr.span,
+                        "you need to pin and box this expression",
+                        format!("Box::pin({})", snippet),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+            true
+        } else {
+            false
+        }
+    }
+
+    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return expression in a block would make sense on its own as a
+    /// statement and the return type has been left as default or has been specified as `()`. If so,
+    /// it suggests adding a semicolon.
+    fn suggest_missing_semicolon(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expression: &'tcx hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        cause_span: Span,
+    ) {
+        if expected.is_unit() {
+            // `BlockTailExpression` only relevant if the tail expr would be
+            // useful on its own.
+            match expression.kind {
+                ExprKind::Call(..)
+                | ExprKind::MethodCall(..)
+                | ExprKind::Loop(..)
+                | ExprKind::Match(..)
+                | ExprKind::Block(..) => {
+                    err.span_suggestion(
+                        cause_span.shrink_to_hi(),
+                        "try adding a semicolon",
+                        ";".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+                _ => (),
+            }
+        }
+    }
+
+    /// A possible error is to forget to add a return type that is needed:
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return type is left as default, the method is not part of an
+    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
+    /// type.
+    pub(in super::super) fn suggest_missing_return_type(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        fn_decl: &hir::FnDecl<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        can_suggest: bool,
+    ) -> bool {
+        // Only suggest changing the return type for methods that
+        // haven't set a return type at all (and aren't `fn main()` or an impl).
+        match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
+            (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
+                err.span_suggestion(
+                    span,
+                    "try adding a return type",
+                    format!("-> {} ", self.resolve_vars_with_obligations(found)),
+                    Applicability::MachineApplicable,
+                );
+                true
+            }
+            (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
+                err.span_label(span, "possibly return type missing here?");
+                true
+            }
+            (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
+                // `fn main()` must return `()`, do not suggest changing return type
+                err.span_label(span, "expected `()` because of default return type");
+                true
+            }
+            // expectation was caused by something else, not the default return
+            (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
+            (&hir::FnRetTy::Return(ref ty), _, _, _) => {
+                // Only point to return type if the expected type is the return type, as if they
+                // are not, the expectation must have been caused by something else.
+                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
+                let sp = ty.span;
+                let ty = AstConv::ast_ty_to_ty(self, ty);
+                debug!("suggest_missing_return_type: return type {:?}", ty);
+                debug!("suggest_missing_return_type: expected type {:?}", ty);
+                if ty.kind() == expected.kind() {
+                    err.span_label(sp, format!("expected `{}` because of return type", expected));
+                    return true;
+                }
+                false
+            }
+        }
+    }
+
+    /// A possible error is to forget to add `.await` when using futures:
+    ///
+    /// ```
+    /// async fn make_u32() -> u32 {
+    ///     22
+    /// }
+    ///
+    /// fn take_u32(x: u32) {}
+    ///
+    /// async fn foo() {
+    ///     let x = make_u32();
+    ///     take_u32(x);
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
+    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
+    /// `.await` to the tail of the expression.
+    pub(in super::super) fn suggest_missing_await(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
+        // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
+        // body isn't `async`.
+        let item_id = self.tcx().hir().get_parent_node(self.body_id);
+        if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
+            let body = self.tcx().hir().body(body_id);
+            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
+                let sp = expr.span;
+                // Check for `Future` implementations by constructing a predicate to
+                // prove: `<T as Future>::Output == U`
+                let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
+                let item_def_id = self
+                    .tcx
+                    .associated_items(future_trait)
+                    .in_definition_order()
+                    .next()
+                    .unwrap()
+                    .def_id;
+                // `<T as Future>::Output`
+                let projection_ty = ty::ProjectionTy {
+                    // `T`
+                    substs: self
+                        .tcx
+                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
+                    // `Future::Output`
+                    item_def_id,
+                };
+
+                let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
+                    projection_ty,
+                    ty: expected,
+                })
+                .potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
+                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
+
+                debug!("suggest_missing_await: trying obligation {:?}", obligation);
+
+                if self.infcx.predicate_may_hold(&obligation) {
+                    debug!("suggest_missing_await: obligation held: {:?}", obligation);
+                    if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
+                        err.span_suggestion(
+                            sp,
+                            "consider using `.await` here",
+                            format!("{}.await", code),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        debug!("suggest_missing_await: no snippet for {:?}", sp);
+                    }
+                } else {
+                    debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
+                }
+            }
+        }
+    }
+
+    pub(in super::super) fn suggest_missing_parentheses(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+    ) {
+        let sp = self.tcx.sess.source_map().start_point(expr.span);
+        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 93fdf93..4473aa2 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -8,11 +8,13 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Expr, ExprKind, Pat, PatKind};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_middle::middle::region::{self, YieldData};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
+use smallvec::SmallVec;
 
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -21,6 +23,13 @@
     expr_count: usize,
     kind: hir::GeneratorKind,
     prev_unresolved_span: Option<Span>,
+    /// Match arm guards have temporary borrows from the pattern bindings.
+    /// In case there is a yield point in a guard with a reference to such bindings,
+    /// such borrows can span across this yield point.
+    /// As such, we need to track these borrows and record them despite of the fact
+    /// that they may succeed the said yield point in the post-order.
+    guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
+    guard_bindings_set: HirIdSet,
 }
 
 impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
@@ -30,6 +39,7 @@
         scope: Option<region::Scope>,
         expr: Option<&'tcx Expr<'tcx>>,
         source_span: Span,
+        guard_borrowing_from_pattern: bool,
     ) {
         use rustc_span::DUMMY_SP;
 
@@ -53,7 +63,12 @@
                         yield_data.expr_and_pat_count, self.expr_count, source_span
                     );
 
-                    if yield_data.expr_and_pat_count >= self.expr_count {
+                    // If it is a borrowing happening in the guard,
+                    // it needs to be recorded regardless because they
+                    // do live across this yield point.
+                    if guard_borrowing_from_pattern
+                        || yield_data.expr_and_pat_count >= self.expr_count
+                    {
                         Some(yield_data)
                     } else {
                         None
@@ -134,6 +149,8 @@
         expr_count: 0,
         kind,
         prev_unresolved_span: None,
+        guard_bindings: <_>::default(),
+        guard_bindings_set: <_>::default(),
     };
     intravisit::walk_body(&mut visitor, body);
 
@@ -210,6 +227,35 @@
         NestedVisitorMap::None
     }
 
+    fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
+        let Arm { guard, pat, body, .. } = arm;
+        self.visit_pat(pat);
+        if let Some(ref g) = guard {
+            self.guard_bindings.push(<_>::default());
+            ArmPatCollector {
+                guard_bindings_set: &mut self.guard_bindings_set,
+                guard_bindings: self
+                    .guard_bindings
+                    .last_mut()
+                    .expect("should have pushed at least one earlier"),
+            }
+            .visit_pat(pat);
+
+            match g {
+                Guard::If(ref e) => {
+                    self.visit_expr(e);
+                }
+            }
+
+            let mut scope_var_ids =
+                self.guard_bindings.pop().expect("should have pushed at least one earlier");
+            for var_id in scope_var_ids.drain(..) {
+                self.guard_bindings_set.remove(&var_id);
+            }
+        }
+        self.visit_expr(body);
+    }
+
     fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
         intravisit::walk_pat(self, pat);
 
@@ -218,11 +264,12 @@
         if let PatKind::Binding(..) = pat.kind {
             let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
             let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
-            self.record(ty, Some(scope), None, pat.span);
+            self.record(ty, Some(scope), None, pat.span, false);
         }
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let mut guard_borrowing_from_pattern = false;
         match &expr.kind {
             ExprKind::Call(callee, args) => match &callee.kind {
                 ExprKind::Path(qpath) => {
@@ -249,6 +296,16 @@
                 }
                 _ => intravisit::walk_expr(self, expr),
             },
+            ExprKind::Path(qpath) => {
+                intravisit::walk_expr(self, expr);
+                let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id);
+                match res {
+                    Res::Local(id) if self.guard_bindings_set.contains(&id) => {
+                        guard_borrowing_from_pattern = true;
+                    }
+                    _ => {}
+                }
+            }
             _ => intravisit::walk_expr(self, expr),
         }
 
@@ -259,7 +316,7 @@
         // If there are adjustments, then record the final type --
         // this is the actual value that is being produced.
         if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
-            self.record(adjusted_ty, scope, Some(expr), expr.span);
+            self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
         }
 
         // Also record the unadjusted type (which is the only type if
@@ -267,10 +324,10 @@
         // unadjusted value is sometimes a "temporary" that would wind
         // up in a MIR temporary.
         //
-        // As an example, consider an expression like `vec![].push()`.
+        // As an example, consider an expression like `vec![].push(x)`.
         // Here, the `vec![]` would wind up MIR stored into a
         // temporary variable `t` which we can borrow to invoke
-        // `<Vec<_>>::push(&mut t)`.
+        // `<Vec<_>>::push(&mut t, x)`.
         //
         // Note that an expression can have many adjustments, and we
         // are just ignoring those intermediate types. This is because
@@ -287,9 +344,30 @@
         // The type table might not have information for this expression
         // if it is in a malformed scope. (#66387)
         if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
-            self.record(ty, scope, Some(expr), expr.span);
+            self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
         } else {
             self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
         }
     }
 }
+
+struct ArmPatCollector<'a> {
+    guard_bindings_set: &'a mut HirIdSet,
+    guard_bindings: &'a mut SmallVec<[HirId; 4]>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
+    type Map = intravisit::ErasedMap<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
+        intravisit::walk_pat(self, pat);
+        if let PatKind::Binding(_, id, ..) = pat.kind {
+            self.guard_bindings.push(id);
+            self.guard_bindings_set.insert(id);
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 2ee867c..f40a250 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -328,14 +328,14 @@
 
             kw::Try => {
                 let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
-                let try_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
+                let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig(
                     iter::once(mut_u8),
                     tcx.mk_unit(),
                     false,
                     hir::Unsafety::Normal,
                     Abi::Rust,
                 ));
-                let catch_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(
+                let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig(
                     [mut_u8, mut_u8].iter().cloned(),
                     tcx.mk_unit(),
                     false,
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index c1ba292..d403e25 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -796,29 +796,29 @@
         // FIXME: do we want to commit to this behavior for param bounds?
         debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
 
-        let bounds =
-            self.param_env.caller_bounds().iter().map(ty::Predicate::skip_binders).filter_map(
-                |predicate| match predicate {
-                    ty::PredicateAtom::Trait(trait_predicate, _) => {
-                        match trait_predicate.trait_ref.self_ty().kind() {
-                            ty::Param(ref p) if *p == param_ty => {
-                                Some(ty::Binder::bind(trait_predicate.trait_ref))
-                            }
-                            _ => None,
+        let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
+            let bound_predicate = predicate.bound_atom();
+            match bound_predicate.skip_binder() {
+                ty::PredicateAtom::Trait(trait_predicate, _) => {
+                    match *trait_predicate.trait_ref.self_ty().kind() {
+                        ty::Param(p) if p == param_ty => {
+                            Some(bound_predicate.rebind(trait_predicate.trait_ref))
                         }
+                        _ => None,
                     }
-                    ty::PredicateAtom::Subtype(..)
-                    | ty::PredicateAtom::Projection(..)
-                    | ty::PredicateAtom::RegionOutlives(..)
-                    | ty::PredicateAtom::WellFormed(..)
-                    | ty::PredicateAtom::ObjectSafe(..)
-                    | ty::PredicateAtom::ClosureKind(..)
-                    | ty::PredicateAtom::TypeOutlives(..)
-                    | ty::PredicateAtom::ConstEvaluatable(..)
-                    | ty::PredicateAtom::ConstEquate(..)
-                    | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
-                },
-            );
+                }
+                ty::PredicateAtom::Subtype(..)
+                | ty::PredicateAtom::Projection(..)
+                | ty::PredicateAtom::RegionOutlives(..)
+                | ty::PredicateAtom::WellFormed(..)
+                | ty::PredicateAtom::ObjectSafe(..)
+                | ty::PredicateAtom::ClosureKind(..)
+                | ty::PredicateAtom::TypeOutlives(..)
+                | ty::PredicateAtom::ConstEvaluatable(..)
+                | ty::PredicateAtom::ConstEquate(..)
+                | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+            }
+        });
 
         self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
             let trait_ref = this.erase_late_bound_regions(&poly_trait_ref);
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index e33a4e9..6d2ffad 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -637,9 +637,10 @@
                         }
                     };
                     let mut format_pred = |pred: ty::Predicate<'tcx>| {
-                        match pred.skip_binders() {
+                        let bound_predicate = pred.bound_atom();
+                        match bound_predicate.skip_binder() {
                             ty::PredicateAtom::Projection(pred) => {
-                                let pred = ty::Binder::bind(pred);
+                                let pred = bound_predicate.rebind(pred);
                                 // `<Foo as Iterator>::Item = String`.
                                 let trait_ref =
                                     pred.skip_binder().projection_ty.trait_ref(self.tcx);
@@ -658,8 +659,7 @@
                                 Some((obligation, trait_ref.self_ty()))
                             }
                             ty::PredicateAtom::Trait(poly_trait_ref, _) => {
-                                let poly_trait_ref = ty::Binder::bind(poly_trait_ref);
-                                let p = poly_trait_ref.skip_binder().trait_ref;
+                                let p = poly_trait_ref.trait_ref;
                                 let self_ty = p.self_ty();
                                 let path = p.print_only_trait_path();
                                 let obligation = format!("{}: {}", self_ty, path);
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 97172d3..169ad0d 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -96,7 +96,7 @@
 pub use check::{check_item_type, check_wf_new};
 pub use diverges::Diverges;
 pub use expectation::Expectation;
-pub use fn_ctxt::FnCtxt;
+pub use fn_ctxt::*;
 pub use inherited::{Inherited, InheritedBuilder};
 
 use crate::astconv::AstConv;
@@ -111,6 +111,7 @@
 use rustc_hir::{HirIdMap, Node};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -264,7 +265,7 @@
 }
 
 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
-    tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
+    tcx.calculate_dtor(def_id, dropck::check_drop_impl)
 }
 
 /// If this `DefId` is a "primary tables entry", returns
@@ -528,7 +529,20 @@
                     hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
                     _ => None,
                 })
-                .unwrap_or_else(fallback);
+                .unwrap_or_else(|| match tcx.hir().get(id) {
+                    Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
+                        Node::Expr(&hir::Expr {
+                            kind: hir::ExprKind::ConstBlock(ref anon_const),
+                            ..
+                        }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span,
+                        }),
+                        _ => fallback(),
+                    },
+                    _ => fallback(),
+                });
+
             let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
             fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
 
@@ -850,7 +864,8 @@
     let mut projections = vec![];
     for (predicate, _) in predicates.predicates {
         debug!("predicate {:?}", predicate);
-        match predicate.skip_binders() {
+        let bound_predicate = predicate.bound_atom();
+        match bound_predicate.skip_binder() {
             ty::PredicateAtom::Trait(trait_predicate, _) => {
                 let entry = types.entry(trait_predicate.self_ty()).or_default();
                 let def_id = trait_predicate.def_id();
@@ -861,7 +876,7 @@
                 }
             }
             ty::PredicateAtom::Projection(projection_pred) => {
-                projections.push(ty::Binder::bind(projection_pred));
+                projections.push(bound_predicate.rebind(projection_pred));
             }
             _ => {}
         }
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 66975f3..02268b1 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -2,6 +2,7 @@
 
 use super::method::MethodCallee;
 use super::FnCtxt;
+use rustc_ast as ast;
 use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -13,6 +14,7 @@
 use rustc_middle::ty::{
     self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor,
 };
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -300,7 +302,7 @@
                                 true,
                             ),
                             hir::BinOpKind::Mul => (
-                                format!("cannot multiply `{}` to `{}`", rhs_ty, lhs_ty),
+                                format!("cannot multiply `{}` by `{}`", lhs_ty, rhs_ty),
                                 Some("std::ops::Mul"),
                                 true,
                             ),
@@ -673,6 +675,29 @@
                     match actual.kind() {
                         Uint(_) if op == hir::UnOp::UnNeg => {
                             err.note("unsigned values cannot be negated");
+
+                            if let hir::ExprKind::Unary(
+                                _,
+                                hir::Expr {
+                                    kind:
+                                        hir::ExprKind::Lit(Spanned {
+                                            node: ast::LitKind::Int(1, _),
+                                            ..
+                                        }),
+                                    ..
+                                },
+                            ) = ex.kind
+                            {
+                                err.span_suggestion(
+                                    ex.span,
+                                    &format!(
+                                        "you may have meant the maximum value of `{}`",
+                                        actual
+                                    ),
+                                    format!("{}::MAX", actual),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                         }
                         Str | Never | Char | Tuple(_) | Array(_, _) => {}
                         Ref(_, ref lty, _) if *lty.kind() == Str => {}
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 321472b..53bc206 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -495,7 +495,7 @@
             self.tcx.sess,
             span,
             E0029,
-            "only char and numeric types are allowed in range patterns"
+            "only `char` and numeric types are allowed in range patterns"
         );
         let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty);
         let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
@@ -1381,7 +1381,7 @@
     /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to
     /// inaccessible fields.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error: pattern requires `..` due to inaccessible fields
     ///   --> src/main.rs:10:9
     ///    |
@@ -1431,7 +1431,7 @@
 
     /// Returns a diagnostic reporting a struct pattern which does not mention some fields.
     ///
-    /// ```ignore (diagnostic)
+    /// ```text
     /// error[E0027]: pattern does not mention field `you_cant_use_this_field`
     ///   --> src/main.rs:15:9
     ///    |
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 2c3be0d..1e97bd6 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -202,9 +202,11 @@
             "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
             closure_hir_id, substs, final_upvar_tys
         );
-        for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) {
-            self.demand_suptype(span, upvar_ty, final_upvar_ty);
-        }
+
+        // Build a tuple (U0..Un) of the final upvar types U0..Un
+        // and unify the upvar tupe type in the closure with it:
+        let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
+        self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
 
         // If we are also inferred the closure kind here,
         // process any deferred resolutions.
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 5203f3f..b4e950a 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -420,6 +420,9 @@
                 check_method_receiver(fcx, hir_sig, &item, self_ty);
             }
             ty::AssocKind::Type => {
+                if let ty::AssocItemContainer::TraitContainer(_) = item.container {
+                    check_associated_type_bounds(fcx, item, span)
+                }
                 if item.defaultness.has_value() {
                     let ty = fcx.tcx.type_of(item.def_id);
                     let ty = fcx.normalize_associated_types_in(span, &ty);
@@ -571,7 +574,6 @@
 
     for_item(tcx, item).with_fcx(|fcx, _| {
         check_where_clauses(tcx, fcx, item.span, trait_def_id.to_def_id(), None);
-        check_associated_type_defaults(fcx, trait_def_id.to_def_id());
 
         vec![]
     });
@@ -581,96 +583,26 @@
 ///
 /// Assuming the defaults are used, check that all predicates (bounds on the
 /// assoc type and where clauses on the trait) hold.
-fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) {
+fn check_associated_type_bounds(fcx: &FnCtxt<'_, '_>, item: &ty::AssocItem, span: Span) {
     let tcx = fcx.tcx;
-    let substs = InternalSubsts::identity_for_item(tcx, trait_def_id);
 
-    // For all assoc. types with defaults, build a map from
-    // `<Self as Trait<...>>::Assoc` to the default type.
-    let map = tcx
-        .associated_items(trait_def_id)
-        .in_definition_order()
-        .filter_map(|item| {
-            if item.kind == ty::AssocKind::Type && item.defaultness.has_value() {
-                // `<Self as Trait<...>>::Assoc`
-                let proj = ty::ProjectionTy { substs, item_def_id: item.def_id };
-                let default_ty = tcx.type_of(item.def_id);
-                debug!("assoc. type default mapping: {} -> {}", proj, default_ty);
-                Some((proj, default_ty))
-            } else {
-                None
-            }
-        })
-        .collect::<FxHashMap<_, _>>();
+    let bounds = tcx.explicit_item_bounds(item.def_id);
 
-    /// Replaces projections of associated types with their default types.
-    ///
-    /// This does a "shallow substitution", meaning that defaults that refer to
-    /// other defaulted assoc. types will still refer to the projection
-    /// afterwards, not to the other default. For example:
-    ///
-    /// ```compile_fail
-    /// trait Tr {
-    ///     type A: Clone = Vec<Self::B>;
-    ///     type B = u8;
-    /// }
-    /// ```
-    ///
-    /// This will end up replacing the bound `Self::A: Clone` with
-    /// `Vec<Self::B>: Clone`, not with `Vec<u8>: Clone`. If we did a deep
-    /// substitution and ended up with the latter, the trait would be accepted.
-    /// If an `impl` then replaced `B` with something that isn't `Clone`,
-    /// suddenly the default for `A` is no longer valid. The shallow
-    /// substitution forces the trait to add a `B: Clone` bound to be accepted,
-    /// which means that an `impl` can replace any default without breaking
-    /// others.
-    ///
-    /// Note that this isn't needed for soundness: The defaults would still be
-    /// checked in any impl that doesn't override them.
-    struct DefaultNormalizer<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        map: FxHashMap<ty::ProjectionTy<'tcx>, Ty<'tcx>>,
-    }
+    debug!("check_associated_type_bounds: bounds={:?}", bounds);
+    let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
+        let normalized_bound = fcx.normalize_associated_types_in(span, &bound);
+        traits::wf::predicate_obligations(
+            fcx,
+            fcx.param_env,
+            fcx.body_id,
+            normalized_bound,
+            bound_span,
+        )
+    });
 
-    impl<'tcx> ty::fold::TypeFolder<'tcx> for DefaultNormalizer<'tcx> {
-        fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-            self.tcx
-        }
-
-        fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-            match t.kind() {
-                ty::Projection(proj_ty) => {
-                    if let Some(default) = self.map.get(&proj_ty) {
-                        default
-                    } else {
-                        t.super_fold_with(self)
-                    }
-                }
-                _ => t.super_fold_with(self),
-            }
-        }
-    }
-
-    // Now take all predicates defined on the trait, replace any mention of
-    // the assoc. types with their default, and prove them.
-    // We only consider predicates that directly mention the assoc. type.
-    let mut norm = DefaultNormalizer { tcx, map };
-    let predicates = fcx.tcx.predicates_of(trait_def_id);
-    for &(orig_pred, span) in predicates.predicates.iter() {
-        let pred = orig_pred.fold_with(&mut norm);
-        if pred != orig_pred {
-            // Mentions one of the defaulted assoc. types
-            debug!("default suitability check: proving predicate: {} -> {}", orig_pred, pred);
-            let pred = fcx.normalize_associated_types_in(span, &pred);
-            let cause = traits::ObligationCause::new(
-                span,
-                fcx.body_id,
-                traits::ItemObligation(trait_def_id),
-            );
-            let obligation = traits::Obligation::new(cause, fcx.param_env, pred);
-
-            fcx.register_predicate(obligation);
-        }
+    for obligation in wf_obligations {
+        debug!("next obligation cause: {:?}", obligation.cause);
+        fcx.register_predicate(obligation);
     }
 }
 
@@ -1493,7 +1425,7 @@
             .collect()
     }
 
-    fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
+    pub(super) fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec<Ty<'tcx>> {
         match self.tcx.impl_trait_ref(impl_def_id) {
             Some(ref trait_ref) => {
                 // Trait impl: take implied bounds from all types that
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 6fd7277..5363702 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -70,10 +70,8 @@
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
         wbcx.typeck_results.used_trait_imports = used_trait_imports;
 
-        wbcx.typeck_results.closure_captures = mem::replace(
-            &mut self.typeck_results.borrow_mut().closure_captures,
-            Default::default(),
-        );
+        wbcx.typeck_results.closure_captures =
+            mem::take(&mut self.typeck_results.borrow_mut().closure_captures);
 
         if self.is_tainted_by_errors() {
             // FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted.
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index 917fc56..b200996 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -110,7 +110,7 @@
                             )
                             .note(
                                 "implementing a foreign trait is only possible if at \
-                                    least one of the types for which is it implemented is local, \
+                                    least one of the types for which it is implemented is local, \
                                     and no uncovered type parameters appear before that first \
                                     local type",
                             )
@@ -135,7 +135,7 @@
                                 local type",
                                 param_ty,
                             )).note("implementing a foreign trait is only possible if at \
-                                    least one of the types for which is it implemented is local"
+                                    least one of the types for which it is implemented is local"
                             ).note("only traits defined in the current crate can be \
                                     implemented for a type parameter"
                             ).emit();
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index a571bd5..b30fb7b 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -21,8 +21,8 @@
 use crate::errors;
 use crate::middle::resolve_lifetime as rl;
 use rustc_ast as ast;
-use rustc_ast::MetaItemKind;
-use rustc_attr::{list_contains_name, InlineAttr, OptimizeAttr};
+use rustc_ast::{MetaItemKind, NestedMetaItem};
+use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_errors::{struct_span_err, Applicability};
@@ -40,7 +40,7 @@
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
 use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
 use rustc_session::config::SanitizerSet;
 use rustc_session::lint;
@@ -50,6 +50,7 @@
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 
+mod item_bounds;
 mod type_of;
 
 struct OnlySelfBounds(bool);
@@ -68,12 +69,15 @@
     *providers = Providers {
         opt_const_param_of: type_of::opt_const_param_of,
         type_of: type_of::type_of,
+        item_bounds: item_bounds::item_bounds,
+        explicit_item_bounds: item_bounds::explicit_item_bounds,
         generics_of,
         predicates_of,
         predicates_defined_on,
         projection_ty_from_predicates,
         explicit_predicates_of,
         super_predicates_of,
+        trait_explicit_predicates_and_bounds,
         type_param_predicates,
         trait_def,
         adt_def,
@@ -222,6 +226,7 @@
                 hir::GenericParamKind::Const { .. } => {
                     let def_id = self.tcx.hir().local_def_id(param.hir_id);
                     self.tcx.ensure().type_of(def_id);
+                    // FIXME(const_generics:defaults)
                 }
             }
         }
@@ -693,16 +698,25 @@
         // Desugared from `impl Trait`, so visited by the function's return type.
         hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => {}
 
-        hir::ItemKind::OpaqueTy(..)
-        | hir::ItemKind::TyAlias(..)
+        // Don't call `type_of` on opaque types, since that depends on type
+        // checking function bodies. `check_item_type` ensures that it's called
+        // instead.
+        hir::ItemKind::OpaqueTy(..) => {
+            tcx.ensure().generics_of(def_id);
+            tcx.ensure().predicates_of(def_id);
+            tcx.ensure().explicit_item_bounds(def_id);
+        }
+        hir::ItemKind::TyAlias(..)
         | hir::ItemKind::Static(..)
         | hir::ItemKind::Const(..)
         | hir::ItemKind::Fn(..) => {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
-            if let hir::ItemKind::Fn(..) = it.kind {
-                tcx.ensure().fn_sig(def_id);
+            match it.kind {
+                hir::ItemKind::Fn(..) => tcx.ensure().fn_sig(def_id),
+                hir::ItemKind::OpaqueTy(..) => tcx.ensure().item_bounds(def_id),
+                _ => (),
             }
         }
     }
@@ -723,15 +737,25 @@
             tcx.ensure().type_of(def_id);
         }
 
-        hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(_, Some(_)) => {
+        hir::TraitItemKind::Const(..) => {
             tcx.ensure().type_of(def_id);
-            // Account for `const C: _;` and `type T = _;`.
+            // Account for `const C: _;`.
+            let mut visitor = PlaceholderHirTyCollector::default();
+            visitor.visit_trait_item(trait_item);
+            placeholder_type_error(tcx, None, &[], visitor.0, false);
+        }
+
+        hir::TraitItemKind::Type(_, Some(_)) => {
+            tcx.ensure().item_bounds(def_id);
+            tcx.ensure().type_of(def_id);
+            // Account for `type T = _;`.
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_trait_item(trait_item);
             placeholder_type_error(tcx, None, &[], visitor.0, false);
         }
 
         hir::TraitItemKind::Type(_, None) => {
+            tcx.ensure().item_bounds(def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
             let mut visitor = PlaceholderHirTyCollector::default();
@@ -827,7 +851,6 @@
     parent_did: LocalDefId,
 ) -> ty::VariantDef {
     let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
-    let hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.unwrap_or(parent_did));
     let fields = def
         .fields()
         .iter()
@@ -844,11 +867,7 @@
                 seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
             }
 
-            ty::FieldDef {
-                did: fid.to_def_id(),
-                ident: f.ident,
-                vis: ty::Visibility::from_hir(&f.vis, hir_id, tcx),
-            }
+            ty::FieldDef { did: fid.to_def_id(), ident: f.ident, vis: tcx.visibility(fid) }
         })
         .collect();
     let recovered = match def {
@@ -1709,7 +1728,7 @@
 
 /// Returns a list of user-specified type predicates for the definition with ID `def_id`.
 /// N.B., this does not include any implied/inferred constraints.
-fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
 
     debug!("explicit_predicates_of(def_id={:?})", def_id);
@@ -1719,7 +1738,6 @@
 
     let mut is_trait = None;
     let mut is_default_impl_trait = None;
-    let mut is_trait_associated_type = None;
 
     let icx = ItemCtxt::new(tcx, def_id);
     let constness = icx.default_constness_for_trait_bounds();
@@ -1732,12 +1750,7 @@
     let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
 
     let ast_generics = match node {
-        Node::TraitItem(item) => {
-            if let hir::TraitItemKind::Type(bounds, _) = item.kind {
-                is_trait_associated_type = Some((bounds, item.span));
-            }
-            &item.generics
-        }
+        Node::TraitItem(item) => &item.generics,
 
         Node::ImplItem(item) => &item.generics,
 
@@ -1755,44 +1768,38 @@
                 | ItemKind::Struct(_, ref generics)
                 | ItemKind::Union(_, ref generics) => generics,
 
-                ItemKind::Trait(_, _, ref generics, .., items) => {
-                    is_trait = Some((ty::TraitRef::identity(tcx, def_id), items));
+                ItemKind::Trait(_, _, ref generics, ..) => {
+                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
                     generics
                 }
                 ItemKind::TraitAlias(ref generics, _) => {
-                    is_trait = Some((ty::TraitRef::identity(tcx, def_id), &[]));
+                    is_trait = Some(ty::TraitRef::identity(tcx, def_id));
                     generics
                 }
                 ItemKind::OpaqueTy(OpaqueTy {
-                    ref bounds,
+                    bounds: _,
                     impl_trait_fn,
                     ref generics,
                     origin: _,
                 }) => {
-                    let bounds_predicates = ty::print::with_no_queries(|| {
-                        let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                        let opaque_ty = tcx.mk_opaque(def_id, substs);
-
-                        // Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
-                        let bounds = AstConv::compute_bounds(
-                            &icx,
-                            opaque_ty,
-                            bounds,
-                            SizedByDefault::Yes,
-                            tcx.def_span(def_id),
-                        );
-
-                        bounds.predicates(tcx, opaque_ty)
-                    });
                     if impl_trait_fn.is_some() {
-                        // opaque types
-                        return ty::GenericPredicates {
-                            parent: None,
-                            predicates: tcx.arena.alloc_from_iter(bounds_predicates),
-                        };
+                        // return-position impl trait
+                        //
+                        // We don't inherit predicates from the parent here:
+                        // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
+                        // then the return type is `f::<'static, T>::{{opaque}}`.
+                        //
+                        // If we inherited the predicates of `f` then we would
+                        // require that `T: 'static` to show that the return
+                        // type is well-formed.
+                        //
+                        // The only way to have something with this opaque type
+                        // is from the return type of the containing function,
+                        // which will ensure that the function's predicates
+                        // hold.
+                        return ty::GenericPredicates { parent: None, predicates: &[] };
                     } else {
-                        // named opaque types
-                        predicates.extend(bounds_predicates);
+                        // type-alias impl trait
                         generics
                     }
                 }
@@ -1818,7 +1825,7 @@
     // and the explicit where-clauses, but to get the full set of predicates
     // on a trait we need to add in the supertrait bounds and bounds found on
     // associated types.
-    if let Some((_trait_ref, _)) = is_trait {
+    if let Some(_trait_ref) = is_trait {
         predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
     }
 
@@ -1985,24 +1992,6 @@
         }
     }
 
-    // Add predicates from associated type bounds (`type X: Bound`)
-    if tcx.features().generic_associated_types {
-        // New behavior: bounds declared on associate type are predicates of that
-        // associated type. Not the default because it needs more testing.
-        if let Some((bounds, span)) = is_trait_associated_type {
-            let projection_ty =
-                tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id));
-
-            predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span))
-        }
-    } else if let Some((self_trait_ref, trait_items)) = is_trait {
-        // Current behavior: bounds declared on associate type are predicates
-        // of its parent trait.
-        predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
-            trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
-        }))
-    }
-
     if tcx.features().const_evaluatable_checked {
         predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
     }
@@ -2124,6 +2113,69 @@
     collector.preds
 }
 
+fn trait_explicit_predicates_and_bounds(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> ty::GenericPredicates<'_> {
+    assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
+    gather_explicit_predicates_of(tcx, def_id.to_def_id())
+}
+
+fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+    if let DefKind::Trait = tcx.def_kind(def_id) {
+        // Remove bounds on associated types from the predicates, they will be
+        // returned by `explicit_item_bounds`.
+        let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
+        let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+        let is_assoc_item_ty = |ty: Ty<'_>| {
+            // For a predicate from a where clause to become a bound on an
+            // associated type:
+            // * It must use the identity substs of the item.
+            //     * Since any generic parameters on the item are not in scope,
+            //       this means that the item is not a GAT, and its identity
+            //       substs are the same as the trait's.
+            // * It must be an associated type for this trait (*not* a
+            //   supertrait).
+            if let ty::Projection(projection) = ty.kind() {
+                if projection.substs == trait_identity_substs
+                    && tcx.associated_item(projection.item_def_id).container.id() == def_id
+                {
+                    true
+                } else {
+                    false
+                }
+            } else {
+                false
+            }
+        };
+
+        let predicates: Vec<_> = predicates_and_bounds
+            .predicates
+            .iter()
+            .copied()
+            .filter(|(pred, _)| match pred.skip_binders() {
+                ty::PredicateAtom::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
+                ty::PredicateAtom::Projection(proj) => {
+                    !is_assoc_item_ty(proj.projection_ty.self_ty())
+                }
+                ty::PredicateAtom::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+                _ => true,
+            })
+            .collect();
+        if predicates.len() == predicates_and_bounds.predicates.len() {
+            predicates_and_bounds
+        } else {
+            ty::GenericPredicates {
+                parent: predicates_and_bounds.parent,
+                predicates: tcx.arena.alloc_slice(&predicates),
+            }
+        }
+    } else {
+        gather_explicit_predicates_of(tcx, def_id)
+    }
+}
+
 fn projection_ty_from_predicates(
     tcx: TyCtxt<'tcx>,
     key: (
@@ -2146,55 +2198,6 @@
     projection_ty
 }
 
-fn trait_associated_item_predicates(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    self_trait_ref: ty::TraitRef<'tcx>,
-    trait_item_ref: &hir::TraitItemRef,
-) -> Vec<(ty::Predicate<'tcx>, Span)> {
-    let trait_item = tcx.hir().trait_item(trait_item_ref.id);
-    let item_def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
-    let bounds = match trait_item.kind {
-        hir::TraitItemKind::Type(ref bounds, _) => bounds,
-        _ => return Vec::new(),
-    };
-
-    if !tcx.generics_of(item_def_id).params.is_empty() {
-        // For GATs the substs provided to the mk_projection call below are
-        // wrong. We should emit a feature gate error if we get here so skip
-        // this type.
-        tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate");
-        return Vec::new();
-    }
-
-    let assoc_ty = tcx.mk_projection(
-        tcx.hir().local_def_id(trait_item.hir_id).to_def_id(),
-        self_trait_ref.substs,
-    );
-
-    associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span)
-}
-
-fn associated_item_bounds(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    bounds: &'tcx [hir::GenericBound<'tcx>],
-    projection_ty: Ty<'tcx>,
-    span: Span,
-) -> Vec<(ty::Predicate<'tcx>, Span)> {
-    let bounds = AstConv::compute_bounds(
-        &ItemCtxt::new(tcx, def_id),
-        projection_ty,
-        bounds,
-        SizedByDefault::Yes,
-        span,
-    );
-
-    let predicates = bounds.predicates(tcx, projection_ty);
-
-    predicates
-}
-
 /// Converts a specific `GenericBound` from the AST into a set of
 /// predicates that apply to the self type. A vector is returned
 /// because this can be anywhere from zero predicates (`T: ?Sized` adds no
@@ -2537,6 +2540,21 @@
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
         } else if tcx.sess.check_name(attr, sym::used) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+        } else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) {
+            if tcx.fn_sig(id).abi() != abi::Abi::C {
+                struct_span_err!(
+                    tcx.sess,
+                    attr.span,
+                    E0776,
+                    "`#[cmse_nonsecure_entry]` requires C ABI"
+                )
+                .emit();
+            }
+            if !tcx.sess.target.llvm_target.contains("thumbv8m") {
+                struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
+                    .emit();
+            }
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
         } else if tcx.sess.check_name(attr, sym::thread_local) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
         } else if tcx.sess.check_name(attr, sym::track_caller) {
@@ -2624,6 +2642,75 @@
                     }
                 }
             }
+        } else if tcx.sess.check_name(attr, sym::instruction_set) {
+            codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) {
+                Some(MetaItemKind::List(ref items)) => match items.as_slice() {
+                    [NestedMetaItem::MetaItem(set)] => {
+                        let segments =
+                            set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+                        match segments.as_slice() {
+                            [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
+                                if !tcx.sess.target.options.has_thumb_interworking {
+                                    struct_span_err!(
+                                        tcx.sess.diagnostic(),
+                                        attr.span,
+                                        E0779,
+                                        "target does not support `#[instruction_set]`"
+                                    )
+                                    .emit();
+                                    None
+                                } else if segments[1] == sym::a32 {
+                                    Some(InstructionSetAttr::ArmA32)
+                                } else if segments[1] == sym::t32 {
+                                    Some(InstructionSetAttr::ArmT32)
+                                } else {
+                                    unreachable!()
+                                }
+                            }
+                            _ => {
+                                struct_span_err!(
+                                    tcx.sess.diagnostic(),
+                                    attr.span,
+                                    E0779,
+                                    "invalid instruction set specified",
+                                )
+                                .emit();
+                                None
+                            }
+                        }
+                    }
+                    [] => {
+                        struct_span_err!(
+                            tcx.sess.diagnostic(),
+                            attr.span,
+                            E0778,
+                            "`#[instruction_set]` requires an argument"
+                        )
+                        .emit();
+                        None
+                    }
+                    _ => {
+                        struct_span_err!(
+                            tcx.sess.diagnostic(),
+                            attr.span,
+                            E0779,
+                            "cannot specify more than one instruction set"
+                        )
+                        .emit();
+                        None
+                    }
+                },
+                _ => {
+                    struct_span_err!(
+                        tcx.sess.diagnostic(),
+                        attr.span,
+                        E0778,
+                        "must specify an instruction set"
+                    )
+                    .emit();
+                    None
+                }
+            };
         }
     }
 
@@ -2699,6 +2786,14 @@
         }
     });
 
+    // #73631: closures inherit `#[target_feature]` annotations
+    if tcx.features().target_feature_11 && tcx.is_closure(id) {
+        let owner_id = tcx.parent(id).expect("closure should have a parent");
+        codegen_fn_attrs
+            .target_features
+            .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied())
+    }
+
     // If a function uses #[target_feature] it can't be inlined into general
     // purpose functions as they wouldn't have the right target features
     // enabled. For that reason we also forbid #[inline(always)] as it can't be
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
new file mode 100644
index 0000000..9c29cee
--- /dev/null
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -0,0 +1,111 @@
+use super::ItemCtxt;
+use crate::astconv::{AstConv, SizedByDefault};
+use rustc_hir as hir;
+use rustc_infer::traits::util;
+use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::def_id::DefId;
+use rustc_span::Span;
+
+/// For associated types we include both bounds written on the type
+/// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
+///
+/// Note that this filtering is done with the items identity substs to
+/// simplify checking that these bounds are met in impls. This means that
+/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
+/// `hr-associated-type-bound-1.rs`.
+fn associated_type_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    assoc_item_def_id: DefId,
+    bounds: &'tcx [hir::GenericBound<'tcx>],
+    span: Span,
+) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+    let item_ty = tcx.mk_projection(
+        assoc_item_def_id,
+        InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
+    );
+
+    let bounds = AstConv::compute_bounds(
+        &ItemCtxt::new(tcx, assoc_item_def_id),
+        item_ty,
+        bounds,
+        SizedByDefault::Yes,
+        span,
+    );
+
+    let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
+    let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
+
+    let bounds_from_parent =
+        trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.skip_binders() {
+            ty::PredicateAtom::Trait(tr, _) => tr.self_ty() == item_ty,
+            ty::PredicateAtom::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
+            ty::PredicateAtom::TypeOutlives(outlives) => outlives.0 == item_ty,
+            _ => false,
+        });
+
+    let all_bounds = tcx
+        .arena
+        .alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
+    debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
+    all_bounds
+}
+
+/// Opaque types don't inherit bounds from their parent: for return position
+/// impl trait it isn't possible to write a suitable predicate on the
+/// containing function and for type-alias impl trait we don't have a backwards
+/// compatibility issue.
+fn opaque_type_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    opaque_def_id: DefId,
+    bounds: &'tcx [hir::GenericBound<'tcx>],
+    span: Span,
+) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+    let item_ty =
+        tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
+
+    let bounds = ty::print::with_no_queries(|| {
+        AstConv::compute_bounds(
+            &ItemCtxt::new(tcx, opaque_def_id),
+            item_ty,
+            bounds,
+            SizedByDefault::Yes,
+            span,
+        )
+    });
+
+    let bounds = bounds.predicates(tcx, item_ty);
+    debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
+
+    tcx.arena.alloc_slice(&bounds)
+}
+
+pub(super) fn explicit_item_bounds(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> &'_ [(ty::Predicate<'_>, Span)] {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    match tcx.hir().get(hir_id) {
+        hir::Node::TraitItem(hir::TraitItem {
+            kind: hir::TraitItemKind::Type(bounds, _),
+            span,
+            ..
+        }) => associated_type_bounds(tcx, def_id, bounds, *span),
+        hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
+            span,
+            ..
+        }) => opaque_type_bounds(tcx, def_id, bounds, *span),
+        _ => bug!("item_bounds called on {:?}", def_id),
+    }
+}
+
+pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
+    tcx.mk_predicates(
+        util::elaborate_predicates(
+            tcx,
+            tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
+        )
+        .map(|obligation| obligation.predicate),
+    )
+}
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 4b3250a..a754d4d 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -112,12 +112,16 @@
                         tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
                         return None;
                     }
-                    _ => span_bug!(
-                        DUMMY_SP,
-                        "unexpected anon const res {:?} in path: {:?}",
-                        res,
-                        path,
-                    ),
+                    _ => {
+                        // If the user tries to specify generics on a type that does not take them,
+                        // e.g. `usize<T>`, we may hit this branch, in which case we treat it as if
+                        // no arguments have been passed. An error should already have been emitted.
+                        tcx.sess.delay_span_bug(
+                            tcx.def_span(def_id),
+                            &format!("unexpected anon const res {:?} in path: {:?}", res, path),
+                        );
+                        return None;
+                    }
                 };
 
                 generics
@@ -309,6 +313,12 @@
                     tcx.types.usize
                 }
 
+                Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
+                    if anon_const.hir_id == hir_id =>
+                {
+                    tcx.typeck(def_id).node_type(anon_const.hir_id)
+                }
+
                 Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
                     .adt_def(tcx.hir().get_parent_did(hir_id).to_def_id())
                     .repr
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index e16f26c..471909a 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -258,7 +258,10 @@
                 self.consume_exprs(&ia.inputs_exprs);
             }
 
-            hir::ExprKind::Continue(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Err => {}
+            hir::ExprKind::Continue(..)
+            | hir::ExprKind::Lit(..)
+            | hir::ExprKind::ConstBlock(..)
+            | hir::ExprKind::Err => {}
 
             hir::ExprKind::Loop(ref blk, _, _) => {
                 self.walk_block(blk);
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index 60b9467..4cf3efc 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -337,6 +337,7 @@
             infcx,
             tcx.param_env(impl1_def_id),
             tcx.hir().local_def_id_to_hir_id(impl1_def_id),
+            0,
             arg,
             span,
         ) {
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index e8fa2b1..c1fa39e 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -56,6 +56,7 @@
 */
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(array_value_iter)]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
@@ -316,7 +317,7 @@
                 }
             }
 
-            let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
+            let se_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
                 [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))].iter().cloned(),
                 tcx.types.isize,
                 false,
@@ -359,7 +360,7 @@
 
     // this ensures that later parts of type checking can assume that items
     // have valid types and not error
-    // FIXME(matthewjasper) We shouldn't need to do this.
+    // FIXME(matthewjasper) We shouldn't need to use `track_errors`.
     tcx.sess.track_errors(|| {
         tcx.sess.time("type_collecting", || {
             for &module in tcx.hir().krate().modules.keys() {
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 04ead74..f6ac7aa 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -370,6 +370,7 @@
             | hir::ExprKind::Loop(..)
             | hir::ExprKind::Match(..)
             | hir::ExprKind::Lit(..)
+            | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Break(..)
             | hir::ExprKind::Continue(..)
             | hir::ExprKind::Struct(..)
diff --git a/compiler/rustc_typeck/src/variance/mod.rs b/compiler/rustc_typeck/src/variance/mod.rs
index a893f69..1565efb 100644
--- a/compiler/rustc_typeck/src/variance/mod.rs
+++ b/compiler/rustc_typeck/src/variance/mod.rs
@@ -4,7 +4,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/variance.html
 
 use hir::Node;
-use rustc_arena::TypedArena;
+use rustc_arena::DroplessArena;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_middle::ty::query::Providers;
@@ -32,8 +32,8 @@
 
 fn crate_variances(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateVariancesMap<'_> {
     assert_eq!(crate_num, LOCAL_CRATE);
-    let mut arena = TypedArena::default();
-    let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena);
+    let arena = DroplessArena::default();
+    let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &arena);
     let constraints_cx = constraints::add_constraints_from_crate(terms_cx);
     solve::solve_constraints(constraints_cx)
 }
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs
index f61a783..81c858c 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_typeck/src/variance/terms.rs
@@ -9,7 +9,7 @@
 // `InferredIndex` is a newtype'd int representing the index of such
 // a variable.
 
-use rustc_arena::TypedArena;
+use rustc_arena::DroplessArena;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::HirIdMap;
@@ -47,7 +47,7 @@
 
 pub struct TermsContext<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
-    pub arena: &'a TypedArena<VarianceTerm<'a>>,
+    pub arena: &'a DroplessArena,
 
     // For marker types, UnsafeCell, and other lang items where
     // variance is hardcoded, records the item-id and the hardcoded
@@ -64,7 +64,7 @@
 
 pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
-    arena: &'a mut TypedArena<VarianceTerm<'a>>,
+    arena: &'a DroplessArena,
 ) -> TermsContext<'a, 'tcx> {
     let mut terms_cx = TermsContext {
         tcx,
diff --git a/config.toml.example b/config.toml.example
index c5efb8e..e7e37c6 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -13,7 +13,7 @@
 # If it does not match the version that is currently running,
 # `x.py` will prompt you to update it and read the changelog.
 # See `src/bootstrap/CHANGELOG.md` for more information.
-changelog-seen = 1
+changelog-seen = 2
 
 # =============================================================================
 # Global Settings
@@ -370,19 +370,23 @@
 # binary, otherwise they are omitted.
 #
 # Defaults to rust.debug value
-#debug-assertions = debug
+#debug-assertions = rust.debug (boolean)
 
 # Whether or not debug assertions are enabled for the standard library.
 # Overrides the `debug-assertions` option, if defined.
 #
 # Defaults to rust.debug-assertions value
-#debug-assertions-std = debug-assertions
+#debug-assertions-std = rust.debug-assertions (boolean)
 
 # Whether or not to leave debug! and trace! calls in the rust binary.
 # Overrides the `debug-assertions` option, if defined.
 #
 # Defaults to rust.debug-assertions value
-#debug-logging = debug-assertions
+#
+# If you see a message from `tracing` saying
+# `max_level_info` is enabled and means logging won't be shown,
+# set this value to `true`.
+#debug-logging = rust.debug-assertions (boolean)
 
 # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
 # `0` - no debug info
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 8b8cdbf..109c3a0 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -14,8 +14,9 @@
 
 extern "Rust" {
     // These are the magic symbols to call the global allocator.  rustc generates
-    // them from the `#[global_allocator]` attribute if there is one, or uses the
-    // default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`)
+    // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
+    // (the code expanding that attribute macro generates those functions), or to call
+    // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
     // otherwise.
     #[rustc_allocator]
     #[rustc_allocator_nounwind]
@@ -35,7 +36,7 @@
 /// if there is one, or the `std` crate’s default.
 ///
 /// Note: while this type is unstable, the functionality it provides can be
-/// accessed through the [free functions in `alloc`](index.html#functions).
+/// accessed through the [free functions in `alloc`](self#functions).
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Copy, Clone, Default, Debug)]
 pub struct Global;
@@ -145,13 +146,13 @@
 
 impl Global {
     #[inline]
-    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
         match layout.size() {
             0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
             // SAFETY: `layout` is non-zero in size,
             size => unsafe {
                 let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 Ok(NonNull::slice_from_raw_parts(ptr, size))
             },
         }
@@ -165,7 +166,7 @@
         old_layout: Layout,
         new_layout: Layout,
         zeroed: bool,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() >= old_layout.size(),
             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
@@ -183,7 +184,7 @@
                 intrinsics::assume(new_size >= old_layout.size());
 
                 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 if zeroed {
                     raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
                 }
@@ -208,12 +209,12 @@
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for Global {
     #[inline]
-    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         self.alloc_impl(layout, false)
     }
 
     #[inline]
-    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         self.alloc_impl(layout, true)
     }
 
@@ -232,7 +233,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: all conditions must be upheld by the caller
         unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
     }
@@ -243,7 +244,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: all conditions must be upheld by the caller
         unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
     }
@@ -254,7 +255,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() <= old_layout.size(),
             "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
@@ -273,7 +274,7 @@
                 intrinsics::assume(new_size <= old_layout.size());
 
                 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
             },
 
@@ -321,6 +322,16 @@
     }
 }
 
+// # Allocation error handler
+
+extern "Rust" {
+    // This is the magic symbol to call the global alloc error handler.  rustc generates
+    // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
+    // default implementations below (`__rdl_oom`) otherwise.
+    #[rustc_allocator_nounwind]
+    fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
+}
+
 /// Abort on memory allocation error or failure.
 ///
 /// Callers of memory allocation APIs wishing to abort computation
@@ -334,6 +345,24 @@
 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
 #[stable(feature = "global_alloc", since = "1.28.0")]
+#[cfg(not(any(test, bootstrap)))]
+#[rustc_allocator_nounwind]
+pub fn handle_alloc_error(layout: Layout) -> ! {
+    unsafe {
+        __rust_alloc_error_handler(layout.size(), layout.align());
+    }
+}
+
+// For alloc test `std::alloc::handle_alloc_error` can be used directly.
+#[cfg(test)]
+pub use std::alloc::handle_alloc_error;
+
+// In stage0 (bootstrap) `__rust_alloc_error_handler`,
+// might not be generated yet, because an old compiler is used,
+// so use the old direct call.
+#[cfg(all(bootstrap, not(test)))]
+#[stable(feature = "global_alloc", since = "1.28.0")]
+#[doc(hidden)]
 #[rustc_allocator_nounwind]
 pub fn handle_alloc_error(layout: Layout) -> ! {
     extern "Rust" {
@@ -342,3 +371,30 @@
     }
     unsafe { oom_impl(layout) }
 }
+
+#[cfg(not(any(test, bootstrap)))]
+#[doc(hidden)]
+#[allow(unused_attributes)]
+#[unstable(feature = "alloc_internals", issue = "none")]
+pub mod __alloc_error_handler {
+    use crate::alloc::Layout;
+
+    // called via generated `__rust_alloc_error_handler`
+
+    // if there is no `#[alloc_error_handler]`
+    #[rustc_std_internal_symbol]
+    pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! {
+        panic!("memory allocation of {} bytes failed", size)
+    }
+
+    // if there is a `#[alloc_error_handler]`
+    #[rustc_std_internal_symbol]
+    pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! {
+        let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
+        extern "Rust" {
+            #[lang = "oom"]
+            fn oom_impl(layout: Layout) -> !;
+        }
+        unsafe { oom_impl(layout) }
+    }
+}
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 5c8c2c5..0fc81cb 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -815,7 +815,7 @@
 
 #[stable(feature = "boxed_str_conv", since = "1.19.0")]
 impl From<Box<str>> for Box<[u8]> {
-    /// Converts a `Box<str>>` into a `Box<[u8]>`
+    /// Converts a `Box<str>` into a `Box<[u8]>`
     ///
     /// This conversion does not allocate on the heap and happens in place.
     ///
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index b4e9929..20c6ebd 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -9,12 +9,13 @@
 use core::ptr;
 
 use super::borrow::DormantMutRef;
-use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef};
+use super::node::{self, marker, ForceResult::*, Handle, NodeRef};
 use super::search::{self, SearchResult::*};
 use super::unwrap_unchecked;
 
+mod entry;
+pub use entry::{Entry, OccupiedEntry, VacantEntry};
 use Entry::*;
-use UnderflowResult::*;
 
 /// A map based on a B-Tree.
 ///
@@ -297,14 +298,23 @@
     length: usize,
 }
 
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+impl<K, V> IntoIter<K, V> {
+    /// Returns an iterator of references over the remaining items.
+    #[inline]
+    pub(super) fn iter(&self) -> Iter<'_, K, V> {
         let range = Range {
             front: self.front.as_ref().map(|f| f.reborrow()),
             back: self.back.as_ref().map(|b| b.reborrow()),
         };
-        f.debug_list().entries(range).finish()
+
+        Iter { range: range, length: self.length }
+    }
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.iter()).finish()
     }
 }
 
@@ -351,11 +361,17 @@
 ///
 /// [`values_mut`]: BTreeMap::values_mut
 #[stable(feature = "map_values_mut", since = "1.10.0")]
-#[derive(Debug)]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
 
+#[stable(feature = "map_values_mut", since = "1.10.0")]
+impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
+    }
+}
+
 /// An owning iterator over the keys of a `BTreeMap`.
 ///
 /// This `struct` is created by the [`into_keys`] method on [`BTreeMap`].
@@ -363,11 +379,17 @@
 ///
 /// [`into_keys`]: BTreeMap::into_keys
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-#[derive(Debug)]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K: fmt::Debug, V> fmt::Debug for IntoKeys<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish()
+    }
+}
+
 /// An owning iterator over the values of a `BTreeMap`.
 ///
 /// This `struct` is created by the [`into_values`] method on [`BTreeMap`].
@@ -375,11 +397,17 @@
 ///
 /// [`into_values`]: BTreeMap::into_values
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-#[derive(Debug)]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V: fmt::Debug> fmt::Debug for IntoValues<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
+    }
+}
+
 /// An iterator over a sub-range of entries in a `BTreeMap`.
 ///
 /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its
@@ -425,69 +453,6 @@
     }
 }
 
-/// A view into a single entry in a map, which may either be vacant or occupied.
-///
-/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`].
-///
-/// [`entry`]: BTreeMap::entry
-#[stable(feature = "rust1", since = "1.0.0")]
-pub enum Entry<'a, K: 'a, V: 'a> {
-    /// A vacant entry.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>),
-
-    /// An occupied entry.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>),
-}
-
-#[stable(feature = "debug_btree_map", since = "1.12.0")]
-impl<K: Debug + Ord, V: Debug> Debug for Entry<'_, K, V> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
-            Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
-        }
-    }
-}
-
-/// A view into a vacant entry in a `BTreeMap`.
-/// It is part of the [`Entry`] enum.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct VacantEntry<'a, K: 'a, V: 'a> {
-    key: K,
-    handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
-    dormant_map: DormantMutRef<'a, BTreeMap<K, V>>,
-
-    // Be invariant in `K` and `V`
-    _marker: PhantomData<&'a mut (K, V)>,
-}
-
-#[stable(feature = "debug_btree_map", since = "1.12.0")]
-impl<K: Debug + Ord, V> Debug for VacantEntry<'_, K, V> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("VacantEntry").field(self.key()).finish()
-    }
-}
-
-/// A view into an occupied entry in a `BTreeMap`.
-/// It is part of the [`Entry`] enum.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
-    handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
-    dormant_map: DormantMutRef<'a, BTreeMap<K, V>>,
-
-    // Be invariant in `K` and `V`
-    _marker: PhantomData<&'a mut (K, V)>,
-}
-
-#[stable(feature = "debug_btree_map", since = "1.12.0")]
-impl<K: Debug + Ord, V: Debug> Debug for OccupiedEntry<'_, K, V> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("OccupiedEntry").field("key", self.key()).field("value", self.get()).finish()
-    }
-}
-
 // An iterator for merging two sorted sequences into one
 struct MergeIter<K, V, I: Iterator<Item = (K, V)>> {
     left: Peekable<I>,
@@ -811,7 +776,7 @@
     /// types that can be `==` without being identical. See the [module-level
     /// documentation] for more.
     ///
-    /// [module-level documentation]: crate::collections#insert-and-complex-keys
+    /// [module-level documentation]: index.html#insert-and-complex-keys
     ///
     /// # Examples
     ///
@@ -1187,40 +1152,8 @@
 
         let mut right = Self::new();
         let right_root = Self::ensure_is_owned(&mut right.root);
-        for _ in 0..left_root.height() {
-            right_root.push_internal_level();
-        }
 
-        {
-            let mut left_node = left_root.node_as_mut();
-            let mut right_node = right_root.node_as_mut();
-
-            loop {
-                let mut split_edge = match search::search_node(left_node, key) {
-                    // key is going to the right tree
-                    Found(handle) => handle.left_edge(),
-                    GoDown(handle) => handle,
-                };
-
-                split_edge.move_suffix(&mut right_node);
-
-                match (split_edge.force(), right_node.force()) {
-                    (Internal(edge), Internal(node)) => {
-                        left_node = edge.descend();
-                        right_node = node.first_edge().descend();
-                    }
-                    (Leaf(_), Leaf(_)) => {
-                        break;
-                    }
-                    _ => {
-                        unreachable!();
-                    }
-                }
-            }
-        }
-
-        left_root.fix_right_border();
-        right_root.fix_left_border();
+        left_root.split_off(right_root, key);
 
         if left_root.height() < right_root.height() {
             self.length = left_root.node_as_ref().calc_length();
@@ -1465,6 +1398,14 @@
 #[stable(feature = "fused", since = "1.26.0")]
 impl<K, V> FusedIterator for IterMut<'_, K, V> {}
 
+impl<'a, K, V> IterMut<'a, K, V> {
+    /// Returns an iterator of references over the remaining items.
+    #[inline]
+    pub(super) fn iter(&self) -> Iter<'_, K, V> {
+        Iter { range: self.range.iter(), length: self.length }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V> IntoIterator for BTreeMap<K, V> {
     type Item = (K, V);
@@ -1666,10 +1607,14 @@
 /// Most of the implementation of DrainFilter, independent of the type
 /// of the predicate, thus also serving for BTreeSet::DrainFilter.
 pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> {
+    /// Reference to the length field in the borrowed map, updated live.
     length: &'a mut usize,
-    // dormant_root is wrapped in an Option to be able to `take` it.
+    /// Burried reference to the root field in the borrowed map.
+    /// Wrapped in `Option` to allow drop handler to `take` it.
     dormant_root: Option<DormantMutRef<'a, node::Root<K, V>>>,
-    // cur_leaf_edge is wrapped in an Option because maps without root lack a leaf edge.
+    /// Contains a leaf edge preceding the next element to be returned, or the last leaf edge.
+    /// Empty if the map has no root, if iteration went beyond the last leaf edge,
+    /// or if a panic occurred in the predicate.
     cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
 }
 
@@ -1744,6 +1689,10 @@
 
     /// Implementation of a typical `DrainFilter::size_hint` method.
     pub(super) fn size_hint(&self) -> (usize, Option<usize>) {
+        // In most of the btree iterators, `self.length` is the number of elements
+        // yet to be visited. Here, it includes elements that were visited and that
+        // the predicate decided not to drain. Making this upper bound more accurate
+        // requires maintaining an extra field and is not worth while.
         (0, Some(*self.length))
     }
 }
@@ -1949,6 +1898,15 @@
     unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
         unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
     }
+
+    /// Returns an iterator of references over the remaining items.
+    #[inline]
+    pub(super) fn iter(&self) -> Range<'_, K, V> {
+        Range {
+            front: self.front.as_ref().map(|f| f.reborrow()),
+            back: self.back.as_ref().map(|b| b.reborrow()),
+        }
+    }
 }
 
 #[stable(feature = "btree_range", since = "1.17.0")]
@@ -2258,596 +2216,6 @@
     }
 }
 
-impl<'a, K: Ord, V> Entry<'a, K, V> {
-    /// Ensures a value is in the entry by inserting the default if empty, and returns
-    /// a mutable reference to the value in the entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    ///
-    /// assert_eq!(map["poneyland"], 12);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or_insert(self, default: V) -> &'a mut V {
-        match self {
-            Occupied(entry) => entry.into_mut(),
-            Vacant(entry) => entry.insert(default),
-        }
-    }
-
-    /// Ensures a value is in the entry by inserting the result of the default function if empty,
-    /// and returns a mutable reference to the value in the entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, String> = BTreeMap::new();
-    /// let s = "hoho".to_string();
-    ///
-    /// map.entry("poneyland").or_insert_with(|| s);
-    ///
-    /// assert_eq!(map["poneyland"], "hoho".to_string());
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
-        match self {
-            Occupied(entry) => entry.into_mut(),
-            Vacant(entry) => entry.insert(default()),
-        }
-    }
-
-    #[unstable(feature = "or_insert_with_key", issue = "71024")]
-    /// Ensures a value is in the entry by inserting, if empty, the result of the default function,
-    /// which takes the key as its argument, and returns a mutable reference to the value in the
-    /// entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(or_insert_with_key)]
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    ///
-    /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count());
-    ///
-    /// assert_eq!(map["poneyland"], 9);
-    /// ```
-    #[inline]
-    pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
-        match self {
-            Occupied(entry) => entry.into_mut(),
-            Vacant(entry) => {
-                let value = default(entry.key());
-                entry.insert(value)
-            }
-        }
-    }
-
-    /// Returns a reference to this entry's key.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
-    /// ```
-    #[stable(feature = "map_entry_keys", since = "1.10.0")]
-    pub fn key(&self) -> &K {
-        match *self {
-            Occupied(ref entry) => entry.key(),
-            Vacant(ref entry) => entry.key(),
-        }
-    }
-
-    /// Provides in-place mutable access to an occupied entry before any
-    /// potential inserts into the map.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    ///
-    /// map.entry("poneyland")
-    ///    .and_modify(|e| { *e += 1 })
-    ///    .or_insert(42);
-    /// assert_eq!(map["poneyland"], 42);
-    ///
-    /// map.entry("poneyland")
-    ///    .and_modify(|e| { *e += 1 })
-    ///    .or_insert(42);
-    /// assert_eq!(map["poneyland"], 43);
-    /// ```
-    #[stable(feature = "entry_and_modify", since = "1.26.0")]
-    pub fn and_modify<F>(self, f: F) -> Self
-    where
-        F: FnOnce(&mut V),
-    {
-        match self {
-            Occupied(mut entry) => {
-                f(entry.get_mut());
-                Occupied(entry)
-            }
-            Vacant(entry) => Vacant(entry),
-        }
-    }
-}
-
-impl<'a, K: Ord, V: Default> Entry<'a, K, V> {
-    #[stable(feature = "entry_or_default", since = "1.28.0")]
-    /// Ensures a value is in the entry by inserting the default value if empty,
-    /// and returns a mutable reference to the value in the entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, Option<usize>> = BTreeMap::new();
-    /// map.entry("poneyland").or_default();
-    ///
-    /// assert_eq!(map["poneyland"], None);
-    /// ```
-    pub fn or_default(self) -> &'a mut V {
-        match self {
-            Occupied(entry) => entry.into_mut(),
-            Vacant(entry) => entry.insert(Default::default()),
-        }
-    }
-}
-
-impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
-    /// Gets a reference to the key that would be used when inserting a value
-    /// through the VacantEntry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
-    /// ```
-    #[stable(feature = "map_entry_keys", since = "1.10.0")]
-    pub fn key(&self) -> &K {
-        &self.key
-    }
-
-    /// Take ownership of the key.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    ///
-    /// if let Entry::Vacant(v) = map.entry("poneyland") {
-    ///     v.into_key();
-    /// }
-    /// ```
-    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
-    pub fn into_key(self) -> K {
-        self.key
-    }
-
-    /// Sets the value of the entry with the `VacantEntry`'s key,
-    /// and returns a mutable reference to it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, u32> = BTreeMap::new();
-    ///
-    /// if let Entry::Vacant(o) = map.entry("poneyland") {
-    ///     o.insert(37);
-    /// }
-    /// assert_eq!(map["poneyland"], 37);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn insert(self, value: V) -> &'a mut V {
-        let out_ptr = match self.handle.insert_recursing(self.key, value) {
-            (Fit(_), val_ptr) => {
-                // Safety: We have consumed self.handle and the handle returned.
-                let map = unsafe { self.dormant_map.awaken() };
-                map.length += 1;
-                val_ptr
-            }
-            (Split(ins), val_ptr) => {
-                drop(ins.left);
-                // Safety: We have consumed self.handle and the reference returned.
-                let map = unsafe { self.dormant_map.awaken() };
-                let root = map.root.as_mut().unwrap();
-                root.push_internal_level().push(ins.k, ins.v, ins.right);
-                map.length += 1;
-                val_ptr
-            }
-        };
-        // Now that we have finished growing the tree using borrowed references,
-        // dereference the pointer to a part of it, that we picked up along the way.
-        unsafe { &mut *out_ptr }
-    }
-}
-
-impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
-    /// Gets a reference to the key in the entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
-    /// ```
-    #[stable(feature = "map_entry_keys", since = "1.10.0")]
-    pub fn key(&self) -> &K {
-        self.handle.reborrow().into_kv().0
-    }
-
-    /// Take ownership of the key and value from the map.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    ///
-    /// if let Entry::Occupied(o) = map.entry("poneyland") {
-    ///     // We delete the entry from the map.
-    ///     o.remove_entry();
-    /// }
-    ///
-    /// // If now try to get the value, it will panic:
-    /// // println!("{}", map["poneyland"]);
-    /// ```
-    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
-    pub fn remove_entry(self) -> (K, V) {
-        self.remove_kv()
-    }
-
-    /// Gets a reference to the value in the entry.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    ///
-    /// if let Entry::Occupied(o) = map.entry("poneyland") {
-    ///     assert_eq!(o.get(), &12);
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get(&self) -> &V {
-        self.handle.reborrow().into_kv().1
-    }
-
-    /// Gets a mutable reference to the value in the entry.
-    ///
-    /// If you need a reference to the `OccupiedEntry` that may outlive the
-    /// destruction of the `Entry` value, see [`into_mut`].
-    ///
-    /// [`into_mut`]: OccupiedEntry::into_mut
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    ///
-    /// assert_eq!(map["poneyland"], 12);
-    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
-    ///     *o.get_mut() += 10;
-    ///     assert_eq!(*o.get(), 22);
-    ///
-    ///     // We can use the same Entry multiple times.
-    ///     *o.get_mut() += 2;
-    /// }
-    /// assert_eq!(map["poneyland"], 24);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut V {
-        self.handle.kv_mut().1
-    }
-
-    /// Converts the entry into a mutable reference to its value.
-    ///
-    /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
-    ///
-    /// [`get_mut`]: OccupiedEntry::get_mut
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    ///
-    /// assert_eq!(map["poneyland"], 12);
-    /// if let Entry::Occupied(o) = map.entry("poneyland") {
-    ///     *o.into_mut() += 10;
-    /// }
-    /// assert_eq!(map["poneyland"], 22);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_mut(self) -> &'a mut V {
-        self.handle.into_val_mut()
-    }
-
-    /// Sets the value of the entry with the `OccupiedEntry`'s key,
-    /// and returns the entry's old value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    ///
-    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
-    ///     assert_eq!(o.insert(15), 12);
-    /// }
-    /// assert_eq!(map["poneyland"], 15);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn insert(&mut self, value: V) -> V {
-        mem::replace(self.get_mut(), value)
-    }
-
-    /// Takes the value of the entry out of the map, and returns it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::BTreeMap;
-    /// use std::collections::btree_map::Entry;
-    ///
-    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
-    /// map.entry("poneyland").or_insert(12);
-    ///
-    /// if let Entry::Occupied(o) = map.entry("poneyland") {
-    ///     assert_eq!(o.remove(), 12);
-    /// }
-    /// // If we try to get "poneyland"'s value, it'll panic:
-    /// // println!("{}", map["poneyland"]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn remove(self) -> V {
-        self.remove_kv().1
-    }
-
-    // Body of `remove_entry`, separate to keep the above implementations short.
-    fn remove_kv(self) -> (K, V) {
-        let mut emptied_internal_root = false;
-        let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true);
-        // SAFETY: we consumed the intermediate root borrow, `self.handle`.
-        let map = unsafe { self.dormant_map.awaken() };
-        map.length -= 1;
-        if emptied_internal_root {
-            let root = map.root.as_mut().unwrap();
-            root.pop_internal_level();
-        }
-        old_kv
-    }
-}
-
-impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
-    /// Removes a key/value-pair from the map, and returns that pair, as well as
-    /// the leaf edge corresponding to that former pair.
-    fn remove_kv_tracking<F: FnOnce()>(
-        self,
-        handle_emptied_internal_root: F,
-    ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
-        let (old_kv, mut pos, was_internal) = match self.force() {
-            Leaf(leaf) => {
-                let (old_kv, pos) = leaf.remove();
-                (old_kv, pos, false)
-            }
-            Internal(mut internal) => {
-                // Replace the location freed in the internal node with an
-                // adjacent KV, and remove that adjacent KV from its leaf.
-                // Always choose the adjacent KV on the left side because
-                // it is typically faster to pop an element from the end
-                // of the KV arrays without needing to shift other elements.
-
-                let key_loc = internal.kv_mut().0 as *mut K;
-                let val_loc = internal.kv_mut().1 as *mut V;
-
-                let to_remove = internal.left_edge().descend().last_leaf_edge().left_kv().ok();
-                let to_remove = unsafe { unwrap_unchecked(to_remove) };
-
-                let (kv, pos) = to_remove.remove();
-
-                let old_key = unsafe { mem::replace(&mut *key_loc, kv.0) };
-                let old_val = unsafe { mem::replace(&mut *val_loc, kv.1) };
-
-                ((old_key, old_val), pos, true)
-            }
-        };
-
-        // Handle underflow
-        let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() };
-        let mut at_leaf = true;
-        while cur_node.len() < node::MIN_LEN {
-            match handle_underfull_node(cur_node) {
-                AtRoot => break,
-                Merged(edge, merged_with_left, offset) => {
-                    // If we merged with our right sibling then our tracked
-                    // position has not changed. However if we merged with our
-                    // left sibling then our tracked position is now dangling.
-                    if at_leaf && merged_with_left {
-                        let idx = pos.idx() + offset;
-                        let node = match unsafe { ptr::read(&edge).descend().force() } {
-                            Leaf(leaf) => leaf,
-                            Internal(_) => unreachable!(),
-                        };
-                        pos = unsafe { Handle::new_edge(node, idx) };
-                    }
-
-                    let parent = edge.into_node();
-                    if parent.len() == 0 {
-                        // The parent that was just emptied must be the root,
-                        // because nodes on a lower level would not have been
-                        // left with a single child.
-                        handle_emptied_internal_root();
-                        break;
-                    } else {
-                        cur_node = parent.forget_type();
-                        at_leaf = false;
-                    }
-                }
-                Stole(stole_from_left) => {
-                    // Adjust the tracked position if we stole from a left sibling
-                    if stole_from_left && at_leaf {
-                        // SAFETY: This is safe since we just added an element to our node.
-                        unsafe {
-                            pos.move_next_unchecked();
-                        }
-                    }
-                    break;
-                }
-            }
-        }
-
-        // If we deleted from an internal node then we need to compensate for
-        // the earlier swap and adjust the tracked position to point to the
-        // next element.
-        if was_internal {
-            pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() };
-        }
-
-        (old_kv, pos)
-    }
-}
-
-impl<K, V> node::Root<K, V> {
-    /// Removes empty levels on the top, but keep an empty leaf if the entire tree is empty.
-    fn fix_top(&mut self) {
-        while self.height() > 0 && self.node_as_ref().len() == 0 {
-            self.pop_internal_level();
-        }
-    }
-
-    fn fix_right_border(&mut self) {
-        self.fix_top();
-
-        {
-            let mut cur_node = self.node_as_mut();
-
-            while let Internal(node) = cur_node.force() {
-                let mut last_kv = node.last_kv();
-
-                if last_kv.can_merge() {
-                    cur_node = last_kv.merge().descend();
-                } else {
-                    let right_len = last_kv.reborrow().right_edge().descend().len();
-                    // `MINLEN + 1` to avoid readjust if merge happens on the next level.
-                    if right_len < node::MIN_LEN + 1 {
-                        last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len);
-                    }
-                    cur_node = last_kv.right_edge().descend();
-                }
-            }
-        }
-
-        self.fix_top();
-    }
-
-    /// The symmetric clone of `fix_right_border`.
-    fn fix_left_border(&mut self) {
-        self.fix_top();
-
-        {
-            let mut cur_node = self.node_as_mut();
-
-            while let Internal(node) = cur_node.force() {
-                let mut first_kv = node.first_kv();
-
-                if first_kv.can_merge() {
-                    cur_node = first_kv.merge().descend();
-                } else {
-                    let left_len = first_kv.reborrow().left_edge().descend().len();
-                    if left_len < node::MIN_LEN + 1 {
-                        first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len);
-                    }
-                    cur_node = first_kv.left_edge().descend();
-                }
-            }
-        }
-
-        self.fix_top();
-    }
-}
-
-enum UnderflowResult<'a, K, V> {
-    AtRoot,
-    Merged(Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::Edge>, bool, usize),
-    Stole(bool),
-}
-
-fn handle_underfull_node<'a, K: 'a, V: 'a>(
-    node: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
-) -> UnderflowResult<'_, K, V> {
-    let parent = match node.ascend() {
-        Ok(parent) => parent,
-        Err(_) => return AtRoot,
-    };
-
-    // Prefer the left KV if it exists. Merging with the left side is faster,
-    // since merging happens towards the left and `node` has fewer elements.
-    // Stealing from the left side is faster, since we can pop from the end of
-    // the KV arrays.
-    let (is_left, mut handle) = match parent.left_kv() {
-        Ok(left) => (true, left),
-        Err(parent) => {
-            let right = unsafe { unwrap_unchecked(parent.right_kv().ok()) };
-            (false, right)
-        }
-    };
-
-    if handle.can_merge() {
-        let offset = if is_left { handle.reborrow().left_edge().descend().len() + 1 } else { 0 };
-        Merged(handle.merge(), is_left, offset)
-    } else {
-        if is_left {
-            handle.steal_left();
-        } else {
-            handle.steal_right();
-        }
-        Stole(is_left)
-    }
-}
-
 impl<K: Ord, V, I: Iterator<Item = (K, V)>> Iterator for MergeIter<K, V, I> {
     type Item = (K, V);
 
diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs
new file mode 100644
index 0000000..73a0ca2
--- /dev/null
+++ b/library/alloc/src/collections/btree/map/entry.rs
@@ -0,0 +1,475 @@
+use core::fmt::{self, Debug};
+use core::marker::PhantomData;
+use core::mem;
+
+use super::super::borrow::DormantMutRef;
+use super::super::node::{marker, Handle, InsertResult::*, NodeRef};
+use super::BTreeMap;
+
+use Entry::*;
+
+/// A view into a single entry in a map, which may either be vacant or occupied.
+///
+/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`].
+///
+/// [`entry`]: BTreeMap::entry
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum Entry<'a, K: 'a, V: 'a> {
+    /// A vacant entry.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>),
+
+    /// An occupied entry.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>),
+}
+
+#[stable(feature = "debug_btree_map", since = "1.12.0")]
+impl<K: Debug + Ord, V: Debug> Debug for Entry<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
+            Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
+        }
+    }
+}
+
+/// A view into a vacant entry in a `BTreeMap`.
+/// It is part of the [`Entry`] enum.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct VacantEntry<'a, K: 'a, V: 'a> {
+    pub(super) key: K,
+    pub(super) handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
+    pub(super) dormant_map: DormantMutRef<'a, BTreeMap<K, V>>,
+
+    // Be invariant in `K` and `V`
+    pub(super) _marker: PhantomData<&'a mut (K, V)>,
+}
+
+#[stable(feature = "debug_btree_map", since = "1.12.0")]
+impl<K: Debug + Ord, V> Debug for VacantEntry<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("VacantEntry").field(self.key()).finish()
+    }
+}
+
+/// A view into an occupied entry in a `BTreeMap`.
+/// It is part of the [`Entry`] enum.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
+    pub(super) handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
+    pub(super) dormant_map: DormantMutRef<'a, BTreeMap<K, V>>,
+
+    // Be invariant in `K` and `V`
+    pub(super) _marker: PhantomData<&'a mut (K, V)>,
+}
+
+#[stable(feature = "debug_btree_map", since = "1.12.0")]
+impl<K: Debug + Ord, V: Debug> Debug for OccupiedEntry<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OccupiedEntry").field("key", self.key()).field("value", self.get()).finish()
+    }
+}
+
+impl<'a, K: Ord, V> Entry<'a, K, V> {
+    /// Ensures a value is in the entry by inserting the default if empty, and returns
+    /// a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn or_insert(self, default: V) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting the result of the default function if empty,
+    /// and returns a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, String> = BTreeMap::new();
+    /// let s = "hoho".to_string();
+    ///
+    /// map.entry("poneyland").or_insert_with(|| s);
+    ///
+    /// assert_eq!(map["poneyland"], "hoho".to_string());
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(default()),
+        }
+    }
+
+    #[unstable(feature = "or_insert_with_key", issue = "71024")]
+    /// Ensures a value is in the entry by inserting, if empty, the result of the default function,
+    /// which takes the key as its argument, and returns a mutable reference to the value in the
+    /// entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(or_insert_with_key)]
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    ///
+    /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count());
+    ///
+    /// assert_eq!(map["poneyland"], 9);
+    /// ```
+    #[inline]
+    pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => {
+                let value = default(entry.key());
+                entry.insert(value)
+            }
+        }
+    }
+
+    /// Returns a reference to this entry's key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
+    #[stable(feature = "map_entry_keys", since = "1.10.0")]
+    pub fn key(&self) -> &K {
+        match *self {
+            Occupied(ref entry) => entry.key(),
+            Vacant(ref entry) => entry.key(),
+        }
+    }
+
+    /// Provides in-place mutable access to an occupied entry before any
+    /// potential inserts into the map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    ///
+    /// map.entry("poneyland")
+    ///    .and_modify(|e| { *e += 1 })
+    ///    .or_insert(42);
+    /// assert_eq!(map["poneyland"], 42);
+    ///
+    /// map.entry("poneyland")
+    ///    .and_modify(|e| { *e += 1 })
+    ///    .or_insert(42);
+    /// assert_eq!(map["poneyland"], 43);
+    /// ```
+    #[stable(feature = "entry_and_modify", since = "1.26.0")]
+    pub fn and_modify<F>(self, f: F) -> Self
+    where
+        F: FnOnce(&mut V),
+    {
+        match self {
+            Occupied(mut entry) => {
+                f(entry.get_mut());
+                Occupied(entry)
+            }
+            Vacant(entry) => Vacant(entry),
+        }
+    }
+}
+
+impl<'a, K: Ord, V: Default> Entry<'a, K, V> {
+    #[stable(feature = "entry_or_default", since = "1.28.0")]
+    /// Ensures a value is in the entry by inserting the default value if empty,
+    /// and returns a mutable reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, Option<usize>> = BTreeMap::new();
+    /// map.entry("poneyland").or_default();
+    ///
+    /// assert_eq!(map["poneyland"], None);
+    /// ```
+    pub fn or_default(self) -> &'a mut V {
+        match self {
+            Occupied(entry) => entry.into_mut(),
+            Vacant(entry) => entry.insert(Default::default()),
+        }
+    }
+}
+
+impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
+    /// Gets a reference to the key that would be used when inserting a value
+    /// through the VacantEntry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
+    #[stable(feature = "map_entry_keys", since = "1.10.0")]
+    pub fn key(&self) -> &K {
+        &self.key
+    }
+
+    /// Take ownership of the key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    ///
+    /// if let Entry::Vacant(v) = map.entry("poneyland") {
+    ///     v.into_key();
+    /// }
+    /// ```
+    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
+    pub fn into_key(self) -> K {
+        self.key
+    }
+
+    /// Sets the value of the entry with the `VacantEntry`'s key,
+    /// and returns a mutable reference to it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, u32> = BTreeMap::new();
+    ///
+    /// if let Entry::Vacant(o) = map.entry("poneyland") {
+    ///     o.insert(37);
+    /// }
+    /// assert_eq!(map["poneyland"], 37);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn insert(self, value: V) -> &'a mut V {
+        let out_ptr = match self.handle.insert_recursing(self.key, value) {
+            (Fit(_), val_ptr) => {
+                // Safety: We have consumed self.handle and the handle returned.
+                let map = unsafe { self.dormant_map.awaken() };
+                map.length += 1;
+                val_ptr
+            }
+            (Split(ins), val_ptr) => {
+                drop(ins.left);
+                // Safety: We have consumed self.handle and the reference returned.
+                let map = unsafe { self.dormant_map.awaken() };
+                let root = map.root.as_mut().unwrap();
+                root.push_internal_level().push(ins.k, ins.v, ins.right);
+                map.length += 1;
+                val_ptr
+            }
+        };
+        // Now that we have finished growing the tree using borrowed references,
+        // dereference the pointer to a part of it, that we picked up along the way.
+        unsafe { &mut *out_ptr }
+    }
+}
+
+impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
+    /// Gets a reference to the key in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    /// assert_eq!(map.entry("poneyland").key(), &"poneyland");
+    /// ```
+    #[stable(feature = "map_entry_keys", since = "1.10.0")]
+    pub fn key(&self) -> &K {
+        self.handle.reborrow().into_kv().0
+    }
+
+    /// Take ownership of the key and value from the map.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     // We delete the entry from the map.
+    ///     o.remove_entry();
+    /// }
+    ///
+    /// // If now try to get the value, it will panic:
+    /// // println!("{}", map["poneyland"]);
+    /// ```
+    #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
+    pub fn remove_entry(self) -> (K, V) {
+        self.remove_kv()
+    }
+
+    /// Gets a reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     assert_eq!(o.get(), &12);
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get(&self) -> &V {
+        self.handle.reborrow().into_kv().1
+    }
+
+    /// Gets a mutable reference to the value in the entry.
+    ///
+    /// If you need a reference to the `OccupiedEntry` that may outlive the
+    /// destruction of the `Entry` value, see [`into_mut`].
+    ///
+    /// [`into_mut`]: OccupiedEntry::into_mut
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+    ///     *o.get_mut() += 10;
+    ///     assert_eq!(*o.get(), 22);
+    ///
+    ///     // We can use the same Entry multiple times.
+    ///     *o.get_mut() += 2;
+    /// }
+    /// assert_eq!(map["poneyland"], 24);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_mut(&mut self) -> &mut V {
+        self.handle.kv_mut().1
+    }
+
+    /// Converts the entry into a mutable reference to its value.
+    ///
+    /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
+    ///
+    /// [`get_mut`]: OccupiedEntry::get_mut
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// assert_eq!(map["poneyland"], 12);
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     *o.into_mut() += 10;
+    /// }
+    /// assert_eq!(map["poneyland"], 22);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_mut(self) -> &'a mut V {
+        self.handle.into_val_mut()
+    }
+
+    /// Sets the value of the entry with the `OccupiedEntry`'s key,
+    /// and returns the entry's old value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
+    ///     assert_eq!(o.insert(15), 12);
+    /// }
+    /// assert_eq!(map["poneyland"], 15);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn insert(&mut self, value: V) -> V {
+        mem::replace(self.get_mut(), value)
+    }
+
+    /// Takes the value of the entry out of the map, and returns it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::BTreeMap;
+    /// use std::collections::btree_map::Entry;
+    ///
+    /// let mut map: BTreeMap<&str, usize> = BTreeMap::new();
+    /// map.entry("poneyland").or_insert(12);
+    ///
+    /// if let Entry::Occupied(o) = map.entry("poneyland") {
+    ///     assert_eq!(o.remove(), 12);
+    /// }
+    /// // If we try to get "poneyland"'s value, it'll panic:
+    /// // println!("{}", map["poneyland"]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn remove(self) -> V {
+        self.remove_kv().1
+    }
+
+    // Body of `remove_entry`, separate to keep the above implementations short.
+    pub(super) fn remove_kv(self) -> (K, V) {
+        let mut emptied_internal_root = false;
+        let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true);
+        // SAFETY: we consumed the intermediate root borrow, `self.handle`.
+        let map = unsafe { self.dormant_map.awaken() };
+        map.length -= 1;
+        if emptied_internal_root {
+            let root = map.root.as_mut().unwrap();
+            root.pop_internal_level();
+        }
+        old_kv
+    }
+}
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index 8018514..b51b95a 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1,34 +1,30 @@
+use super::super::{node, DeterministicRng};
+use super::Entry::{Occupied, Vacant};
+use super::*;
 use crate::boxed::Box;
-use crate::collections::btree::navigate::Position;
-use crate::collections::btree::node;
-use crate::collections::btree_map::Entry::{Occupied, Vacant};
-use crate::collections::BTreeMap;
 use crate::fmt::Debug;
 use crate::rc::Rc;
-use crate::string::String;
-use crate::string::ToString;
+use crate::string::{String, ToString};
 use crate::vec::Vec;
 use std::convert::TryFrom;
-use std::iter::FromIterator;
+use std::iter::{self, FromIterator};
 use std::mem;
 use std::ops::Bound::{self, Excluded, Included, Unbounded};
 use std::ops::RangeBounds;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
-use super::super::DeterministicRng;
-
 // Capacity of a tree with a single level,
-// i.e. a tree who's root is a leaf node at height 0.
+// i.e., a tree who's root is a leaf node at height 0.
 const NODE_CAPACITY: usize = node::CAPACITY;
 
 // Minimum number of elements to insert, to guarantee a tree with 2 levels,
-// i.e. a tree who's root is an internal node at height 1, with edges to leaf nodes.
+// i.e., a tree who's root is an internal node at height 1, with edges to leaf nodes.
 // It's not the minimum size: removing an element from such a tree does not always reduce height.
 const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1;
 
 // Minimum number of elements to insert in ascending order, to guarantee a tree with 3 levels,
-// i.e. a tree who's root is an internal node at height 2, with edges to more internal nodes.
+// i.e., a tree who's root is an internal node at height 2, with edges to more internal nodes.
 // It's not the minimum size: removing an element from such a tree does not always reduce height.
 const MIN_INSERTS_HEIGHT_2: usize = 89;
 
@@ -46,19 +42,6 @@
     }
 }
 
-struct SeriesChecker<T> {
-    previous: Option<T>,
-}
-
-impl<T: Copy + Debug + Ord> SeriesChecker<T> {
-    fn is_ascending(&mut self, next: T) {
-        if let Some(previous) = self.previous {
-            assert!(previous < next, "{:?} >= {:?}", previous, next);
-        }
-        self.previous = Some(next);
-    }
-}
-
 impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
     /// Panics if the map (or the code navigating it) is corrupted.
     fn check(&self)
@@ -67,44 +50,10 @@
     {
         if let Some(root) = &self.root {
             let root_node = root.node_as_ref();
-            let mut checker = SeriesChecker { previous: None };
-            let mut internal_length = 0;
-            let mut internal_kv_count = 0;
-            let mut leaf_length = 0;
-            root_node.visit_nodes_in_order(|pos| match pos {
-                Position::Leaf(node) => {
-                    let is_root = root_node.height() == 0;
-                    let min_len = if is_root { 0 } else { node::MIN_LEN };
-                    assert!(node.len() >= min_len, "{} < {}", node.len(), min_len);
-
-                    for idx in 0..node.len() {
-                        let key = *unsafe { node.key_at(idx) };
-                        checker.is_ascending(key);
-                    }
-                    leaf_length += node.len();
-                }
-                Position::Internal(node) => {
-                    let is_root = root_node.height() == node.height();
-                    let min_len = if is_root { 1 } else { node::MIN_LEN };
-                    assert!(node.len() >= min_len, "{} < {}", node.len(), min_len);
-
-                    for idx in 0..=node.len() {
-                        let edge = unsafe { node::Handle::new_edge(node, idx) };
-                        assert!(edge.descend().ascend().ok().unwrap() == edge);
-                    }
-
-                    internal_length += node.len();
-                }
-                Position::InternalKV(kv) => {
-                    let key = *kv.into_kv().0;
-                    checker.is_ascending(key);
-
-                    internal_kv_count += 1;
-                }
-            });
-            assert_eq!(internal_length, internal_kv_count);
-            assert_eq!(root_node.calc_length(), internal_length + leaf_length);
-            assert_eq!(self.length, internal_length + leaf_length);
+            assert!(root_node.ascend().is_err());
+            root_node.assert_back_pointers();
+            root_node.assert_ascending();
+            assert_eq!(self.length, root_node.assert_and_add_lengths());
         } else {
             assert_eq!(self.length, 0);
         }
@@ -120,28 +69,7 @@
         K: Debug,
     {
         if let Some(root) = self.root.as_ref() {
-            let mut result = String::new();
-            let root_node = root.node_as_ref();
-            root_node.visit_nodes_in_order(|pos| match pos {
-                Position::Leaf(leaf) => {
-                    let depth = root_node.height();
-                    let indent = "  ".repeat(depth);
-                    result += &format!("\n{}", indent);
-                    for idx in 0..leaf.len() {
-                        if idx > 0 {
-                            result += ", ";
-                        }
-                        result += &format!("{:?}", unsafe { leaf.key_at(idx) });
-                    }
-                }
-                Position::Internal(_) => {}
-                Position::InternalKV(kv) => {
-                    let depth = root_node.height() - kv.into_node().height();
-                    let indent = "  ".repeat(depth);
-                    result += &format!("\n{}{:?}", indent, kv.into_kv().0);
-                }
-            });
-            result
+            root.node_as_ref().dump_keys()
         } else {
             String::from("not yet allocated")
         }
@@ -174,7 +102,6 @@
         let last_key = *map.last_key_value().unwrap().0;
         map.insert(last_key + 1, ());
     }
-    println!("{}", map.dump_keys());
     map.check();
     // Structure:
     // - 1 element in internal root node with 2 children
@@ -376,7 +303,7 @@
 fn do_test_iter_mut_mutation<T>(size: usize)
 where
     T: Copy + Debug + Ord + TryFrom<usize>,
-    <T as std::convert::TryFrom<usize>>::Error: std::fmt::Debug,
+    <T as TryFrom<usize>>::Error: Debug,
 {
     let zero = T::try_from(0).unwrap();
     let mut map: BTreeMap<T, T> = (0..size).map(|i| (T::try_from(i).unwrap(), zero)).collect();
@@ -861,7 +788,7 @@
     fn consuming_nothing() {
         let pairs = (0..3).map(|i| (i, i));
         let mut map: BTreeMap<_, _> = pairs.collect();
-        assert!(map.drain_filter(|_, _| false).eq(std::iter::empty()));
+        assert!(map.drain_filter(|_, _| false).eq(iter::empty()));
         map.check();
     }
 
@@ -882,7 +809,7 @@
                 *v += 6;
                 false
             })
-            .eq(std::iter::empty())
+            .eq(iter::empty())
         );
         assert!(map.keys().copied().eq(0..3));
         assert!(map.values().copied().eq(6..9));
@@ -1386,44 +1313,65 @@
     }
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_variance() {
-    use std::collections::btree_map::{IntoIter, Iter, Keys, Range, Values};
-
     fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> {
         v
     }
     fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> {
         v
     }
+
     fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> {
         v
     }
     fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> {
         v
     }
+
     fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> {
         v
     }
     fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> {
         v
     }
+
+    fn into_keys_key<'new>(v: IntoKeys<&'static str, ()>) -> IntoKeys<&'new str, ()> {
+        v
+    }
+    fn into_keys_val<'new>(v: IntoKeys<(), &'static str>) -> IntoKeys<(), &'new str> {
+        v
+    }
+
+    fn into_values_key<'new>(v: IntoValues<&'static str, ()>) -> IntoValues<&'new str, ()> {
+        v
+    }
+    fn into_values_val<'new>(v: IntoValues<(), &'static str>) -> IntoValues<(), &'new str> {
+        v
+    }
+
     fn range_key<'a, 'new>(v: Range<'a, &'static str, ()>) -> Range<'a, &'new str, ()> {
         v
     }
     fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> {
         v
     }
-    fn keys<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> {
+
+    fn keys_key<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> {
         v
     }
-    fn vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> {
+    fn keys_val<'a, 'new>(v: Keys<'a, (), &'static str>) -> Keys<'a, (), &'new str> {
+        v
+    }
+
+    fn values_key<'a, 'new>(v: Values<'a, &'static str, ()>) -> Values<'a, &'new str, ()> {
+        v
+    }
+    fn values_val<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> {
         v
     }
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_sync() {
     fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
@@ -1493,7 +1441,6 @@
     }
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_send() {
     fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send {
@@ -1520,7 +1467,7 @@
         v.iter()
     }
 
-    fn iter_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+    fn iter_mut<T: Send>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
         v.iter_mut()
     }
 
@@ -1532,7 +1479,7 @@
         v.values()
     }
 
-    fn values_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+    fn values_mut<T: Send>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
         v.values_mut()
     }
 
@@ -1540,7 +1487,7 @@
         v.range(..)
     }
 
-    fn range_mut<T: Send + Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
+    fn range_mut<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
         v.range_mut(..)
     }
 
diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs
index ecbdacd..bcc50ed 100644
--- a/library/alloc/src/collections/btree/mod.rs
+++ b/library/alloc/src/collections/btree/mod.rs
@@ -2,8 +2,10 @@
 pub mod map;
 mod navigate;
 mod node;
+mod remove;
 mod search;
 pub mod set;
+mod split;
 
 #[doc(hidden)]
 trait Recover<Q: ?Sized> {
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index c3f27c1..886d8ab 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -9,11 +9,8 @@
 // struct Node<K, V, height: usize> {
 //     keys: [K; 2 * B - 1],
 //     vals: [V; 2 * B - 1],
-//     edges: if height > 0 {
-//         [Box<Node<K, V, height - 1>>; 2 * B]
-//     } else { () },
-//     parent: Option<NonNull<Node<K, V, height + 1>>>,
-//     parent_idx: u16,
+//     edges: [if height > 0 { Box<Node<K, V, height - 1>> } else { () }; 2 * B],
+//     parent: Option<(NonNull<Node<K, V, height + 1>>, u16)>,
 //     len: u16,
 // }
 // ```
@@ -28,8 +25,8 @@
 //
 // - Trees must have uniform depth/height. This means that every path down to a leaf from a
 //   given node has exactly the same length.
-// - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges.
-//   This implies that even an empty internal node has at least one edge.
+// - A node of length `n` has `n` keys, `n` values, and `n + 1` edges.
+//   This implies that even an empty node has at least one edge.
 
 use core::cmp::Ordering;
 use core::marker::PhantomData;
@@ -90,7 +87,6 @@
 #[repr(C)]
 // gdb_providers.py uses this type name for introspection.
 struct InternalNode<K, V> {
-    // gdb_providers.py uses this field name for introspection.
     data: LeafNode<K, V>,
 
     /// The pointers to the children of this node. `len + 1` of these are considered
@@ -128,11 +124,7 @@
     }
 
     fn from_internal(node: Box<InternalNode<K, V>>) -> Self {
-        BoxedNode { ptr: Box::into_unique(node).cast() }
-    }
-
-    unsafe fn from_ptr(ptr: NonNull<LeafNode<K, V>>) -> Self {
-        BoxedNode { ptr: unsafe { Unique::new_unchecked(ptr.as_ptr()) } }
+        BoxedNode { ptr: Unique::from(&mut Box::leak(node).data) }
     }
 
     fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
@@ -173,6 +165,22 @@
         NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
     }
 
+    /// Borrows and returns a mutable reference to the leaf node owned by the root.
+    /// # Safety
+    /// The root node is a leaf.
+    unsafe fn leaf_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Leaf> {
+        debug_assert!(self.height == 0);
+        NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+    }
+
+    /// Borrows and returns a mutable reference to the internal node owned by the root.
+    /// # Safety
+    /// The root node is not a leaf.
+    unsafe fn internal_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
+        debug_assert!(self.height > 0);
+        NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+    }
+
     pub fn node_as_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, marker::LeafOrInternal> {
         NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
     }
@@ -186,19 +194,16 @@
     /// and is the opposite of `pop_internal_level`.
     pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
         let mut new_node = Box::new(unsafe { InternalNode::new() });
-        new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) });
+        new_node.edges[0].write(unsafe { ptr::read(&mut self.node) });
 
         self.node = BoxedNode::from_internal(new_node);
         self.height += 1;
 
-        let mut ret =
-            NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData };
-
         unsafe {
+            let mut ret = self.internal_node_as_mut();
             ret.reborrow_mut().first_edge().correct_parent_link();
+            ret
         }
-
-        ret
     }
 
     /// Removes the internal root node, using its first child as the new root node.
@@ -215,11 +220,8 @@
 
         let top = self.node.ptr;
 
-        self.node = unsafe {
-            BoxedNode::from_ptr(
-                self.node_as_mut().cast_unchecked::<marker::Internal>().first_edge().descend().node,
-            )
-        };
+        let mut internal_node = unsafe { self.internal_node_as_mut() };
+        self.node = unsafe { internal_node.as_internal_mut().edges[0].assume_init_read() };
         self.height -= 1;
         self.node_as_mut().as_leaf_mut().parent = None;
 
@@ -250,8 +252,13 @@
 ///   `NodeRef` points to an internal node, and when this is `LeafOrInternal` the
 ///   `NodeRef` could be pointing to either type of node.
 pub struct NodeRef<BorrowType, K, V, Type> {
-    /// The number of levels below the node.
+    /// The number of levels below the node, a property of the node that cannot be
+    /// entirely described by `Type` and that the node does not store itself either.
+    /// Unconstrained if `Type` is `LeafOrInternal`, must be zero if `Type` is `Leaf`,
+    /// and must be non-zero if `Type` is `Internal`.
     height: usize,
+    /// The pointer to the leaf or internal node. The definition of `InternalNode`
+    /// ensures that the pointer is valid either way.
     node: NonNull<LeafNode<K, V>>,
     _marker: PhantomData<(BorrowType, Type)>,
 }
@@ -298,9 +305,8 @@
 }
 
 impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
-    /// Finds the length of the node. This is the number of keys or values. In an
-    /// internal node, the number of edges is `len() + 1`.
-    /// For any node, the number of possible edge handles is also `len() + 1`.
+    /// Finds the length of the node. This is the number of keys or values.
+    /// The number of edges is `len() + 1`.
     /// Note that, despite being safe, calling this function can have the side effect
     /// of invalidating mutable references that unsafe code has created.
     pub fn len(&self) -> usize {
@@ -309,8 +315,8 @@
         unsafe { usize::from((*self.as_leaf_ptr()).len) }
     }
 
-    /// Returns the height of this node in the whole tree. Zero height denotes the
-    /// leaf level.
+    /// Returns the height of this node with respect to the leaf level. Zero height means the
+    /// node is a leaf itself.
     pub fn height(&self) -> usize {
         self.height
     }
@@ -321,9 +327,6 @@
     }
 
     /// Exposes the leaf portion of any leaf or internal node.
-    /// If the node is a leaf, this function simply opens up its data.
-    /// If the node is an internal node, so not a leaf, it does have all the data a leaf has
-    /// (header, keys and values), and this function exposes that.
     ///
     /// Returns a raw ptr to avoid invalidating other references to this node,
     /// which is possible when BorrowType is marker::ValMut.
@@ -450,9 +453,9 @@
 }
 
 impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// Unsafely asserts to the compiler some static information about whether this
-    /// node is a `Leaf` or an `Internal`.
-    unsafe fn cast_unchecked<NewType>(self) -> NodeRef<marker::Mut<'a>, K, V, NewType> {
+    /// Unsafely asserts to the compiler the static information that this node is an `Internal`.
+    unsafe fn cast_to_internal_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
+        debug_assert!(self.height > 0);
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
     }
 
@@ -471,9 +474,6 @@
     }
 
     /// Exposes the leaf portion of any leaf or internal node for writing.
-    /// If the node is a leaf, this function simply opens up its data.
-    /// If the node is an internal node, so not a leaf, it does have all the data a leaf has
-    /// (header, keys and values), and this function exposes that.
     ///
     /// We don't need to return a raw ptr because we have unique access to the entire node.
     fn as_leaf_mut(&mut self) -> &'a mut LeafNode<K, V> {
@@ -484,7 +484,7 @@
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    pub unsafe fn key_mut_at(&mut self, idx: usize) -> &mut K {
+    unsafe fn key_mut_at(&mut self, idx: usize) -> &mut K {
         unsafe { self.reborrow_mut().into_key_mut_at(idx) }
     }
 
@@ -492,7 +492,7 @@
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    pub unsafe fn val_mut_at(&mut self, idx: usize) -> &mut V {
+    unsafe fn val_mut_at(&mut self, idx: usize) -> &mut V {
         unsafe { self.reborrow_mut().into_val_mut_at(idx) }
     }
 
@@ -584,9 +584,11 @@
         // to avoid aliasing with outstanding references to other elements,
         // in particular, those returned to the caller in earlier iterations.
         let leaf = self.node.as_ptr();
+        let keys = unsafe { &raw const (*leaf).keys };
+        let vals = unsafe { &raw mut (*leaf).vals };
         // We must coerce to unsized array pointers because of Rust issue #74679.
-        let keys: *const [_] = unsafe { &raw const (*leaf).keys };
-        let vals: *mut [_] = unsafe { &raw mut (*leaf).vals };
+        let keys: *const [_] = keys;
+        let vals: *mut [_] = vals;
         // SAFETY: The keys and values of a node must always be initialized up to length.
         let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() };
         let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() };
@@ -609,7 +611,7 @@
 
     /// Adds a key/value pair to the beginning of the node.
     fn push_front(&mut self, key: K, val: V) {
-        debug_assert!(self.len() < CAPACITY);
+        assert!(self.len() < CAPACITY);
 
         unsafe {
             slice_insert(self.keys_mut(), 0, key);
@@ -655,21 +657,14 @@
 
     /// Adds a key/value pair, and an edge to go to the left of that pair,
     /// to the beginning of the node.
-    pub fn push_front(&mut self, key: K, val: V, edge: Root<K, V>) {
+    fn push_front(&mut self, key: K, val: V, edge: Root<K, V>) {
         assert!(edge.height == self.height - 1);
         assert!(self.len() < CAPACITY);
 
         unsafe {
             slice_insert(self.keys_mut(), 0, key);
             slice_insert(self.vals_mut(), 0, val);
-            slice_insert(
-                slice::from_raw_parts_mut(
-                    MaybeUninit::slice_as_mut_ptr(&mut self.as_internal_mut().edges),
-                    self.len() + 1,
-                ),
-                0,
-                edge.node,
-            );
+            slice_insert(self.edges_mut(), 0, edge.node);
         }
 
         self.as_leaf_mut().len += 1;
@@ -679,9 +674,9 @@
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
-    /// Removes a key/value pair from the end of this node and returns the pair.
-    /// If this is an internal node, also removes the edge that was to the right
-    /// of that pair and returns the orphaned node that this edge owned.
+    /// Removes a key/value pair from the end of the node and returns the pair.
+    /// Also removes the edge that was to the right of that pair and, if the node
+    /// is internal, returns the orphaned subtree that this edge owned.
     fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
         debug_assert!(self.len() > 0);
 
@@ -705,9 +700,9 @@
         }
     }
 
-    /// Removes a key/value pair from the beginning of this node and returns the pair.
-    /// If this is an internal node, also removes the edge that was to the left
-    /// of that pair and returns the orphaned node that this edge owned.
+    /// Removes a key/value pair from the beginning of the node and returns the pair.
+    /// Also removes the edge that was to the left of that pair and, if the node is
+    /// internal, returns the orphaned subtree that this edge owned.
     fn pop_front(&mut self) -> (K, V, Option<Root<K, V>>) {
         debug_assert!(self.len() > 0);
 
@@ -817,11 +812,25 @@
     }
 }
 
+impl<BorrowType, K, V, NodeType> NodeRef<BorrowType, K, V, NodeType> {
+    /// Could be a public implementation of PartialEq, but only used in this module.
+    fn eq(&self, other: &Self) -> bool {
+        let Self { node, height, _marker: _ } = self;
+        if *node == other.node {
+            debug_assert_eq!(*height, other.height);
+            true
+        } else {
+            false
+        }
+    }
+}
+
 impl<BorrowType, K, V, NodeType, HandleType> PartialEq
     for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
 {
     fn eq(&self, other: &Self) -> bool {
-        self.node.node == other.node.node && self.idx == other.idx
+        let Self { node, idx, _marker: _ } = self;
+        node.eq(&other.node) && *idx == other.idx
     }
 }
 
@@ -829,7 +838,8 @@
     for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
 {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        if self.node.node == other.node.node { Some(self.idx.cmp(&other.idx)) } else { None }
+        let Self { node, idx, _marker: _ } = self;
+        if node.eq(&other.node) { Some(idx.cmp(&other.idx)) } else { None }
     }
 }
 
@@ -904,24 +914,6 @@
     }
 }
 
-impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::Edge> {
-    /// Helps implementations of `insert_fit` for a particular `NodeType`,
-    /// by taking care of leaf data.
-    /// Inserts a new key/value pair between the key/value pairs to the right and left of
-    /// this edge. This method assumes that there is enough space in the node for the new
-    /// pair to fit.
-    fn leafy_insert_fit(&mut self, key: K, val: V) {
-        debug_assert!(self.node.len() < CAPACITY);
-
-        unsafe {
-            slice_insert(self.node.keys_mut(), self.idx, key);
-            slice_insert(self.node.vals_mut(), self.idx, val);
-
-            self.node.as_leaf_mut().len += 1;
-        }
-    }
-}
-
 impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
     /// Inserts a new key/value pair between the key/value pairs to the right and left of
     /// this edge. This method assumes that there is enough space in the node for the new
@@ -929,8 +921,15 @@
     ///
     /// The returned pointer points to the inserted value.
     fn insert_fit(&mut self, key: K, val: V) -> *mut V {
-        self.leafy_insert_fit(key, val);
-        unsafe { self.node.val_mut_at(self.idx) }
+        debug_assert!(self.node.len() < CAPACITY);
+
+        unsafe {
+            slice_insert(self.node.keys_mut(), self.idx, key);
+            slice_insert(self.node.vals_mut(), self.idx, val);
+            self.node.as_leaf_mut().len += 1;
+
+            self.node.val_mut_at(self.idx)
+        }
     }
 }
 
@@ -953,10 +952,7 @@
                     Handle::new_edge(left.reborrow_mut(), insert_idx)
                 },
                 InsertionPlace::Right(insert_idx) => unsafe {
-                    Handle::new_edge(
-                        right.node_as_mut().cast_unchecked::<marker::Leaf>(),
-                        insert_idx,
-                    )
+                    Handle::new_edge(right.leaf_node_as_mut(), insert_idx)
                 },
             };
             let val_ptr = insertion_edge.insert_fit(key, val);
@@ -982,11 +978,14 @@
     /// between this edge and the key/value pair to the right of this edge. This method assumes
     /// that there is enough space in the node for the new pair to fit.
     fn insert_fit(&mut self, key: K, val: V, edge: Root<K, V>) {
+        debug_assert!(self.node.len() < CAPACITY);
         debug_assert!(edge.height == self.node.height - 1);
 
         unsafe {
+            slice_insert(self.node.keys_mut(), self.idx, key);
+            slice_insert(self.node.vals_mut(), self.idx, val);
             slice_insert(self.node.edges_mut(), self.idx + 1, edge.node);
-            self.leafy_insert_fit(key, val);
+            self.node.as_leaf_mut().len += 1;
 
             self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
         }
@@ -1011,18 +1010,15 @@
             let (middle_kv_idx, insertion) = splitpoint(self.idx);
             let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
             let (mut left, k, v, mut right) = middle.split();
-            match insertion {
+            let mut insertion_edge = match insertion {
                 InsertionPlace::Left(insert_idx) => unsafe {
-                    Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val, edge);
+                    Handle::new_edge(left.reborrow_mut(), insert_idx)
                 },
                 InsertionPlace::Right(insert_idx) => unsafe {
-                    Handle::new_edge(
-                        right.node_as_mut().cast_unchecked::<marker::Internal>(),
-                        insert_idx,
-                    )
-                    .insert_fit(key, val, edge);
+                    Handle::new_edge(right.internal_node_as_mut(), insert_idx)
                 },
-            }
+            };
+            insertion_edge.insert_fit(key, val, edge);
             InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right })
         }
     }
@@ -1121,14 +1117,20 @@
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
     /// Helps implementations of `split` for a particular `NodeType`,
+    /// by calculating the length of the new node.
+    fn split_new_node_len(&self) -> usize {
+        debug_assert!(self.idx < self.node.len());
+        self.node.len() - self.idx - 1
+    }
+
+    /// Helps implementations of `split` for a particular `NodeType`,
     /// by taking care of leaf data.
-    fn leafy_split(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V, usize) {
+    fn split_leaf_data(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V) {
+        let new_len = self.split_new_node_len();
         unsafe {
             let k = ptr::read(self.node.key_at(self.idx));
             let v = ptr::read(self.node.val_at(self.idx));
 
-            let new_len = self.node.len() - self.idx - 1;
-
             ptr::copy_nonoverlapping(
                 self.node.key_at(self.idx + 1),
                 MaybeUninit::slice_as_mut_ptr(&mut new_node.keys),
@@ -1142,7 +1144,7 @@
 
             self.node.as_leaf_mut().len = self.idx as u16;
             new_node.len = new_len as u16;
-            (k, v, new_len)
+            (k, v)
         }
     }
 }
@@ -1150,7 +1152,7 @@
 impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
     /// Splits the underlying node into three parts:
     ///
-    /// - The node is truncated to only contain the key/value pairs to the right of
+    /// - The node is truncated to only contain the key/value pairs to the left of
     ///   this handle.
     /// - The key and value pointed to by this handle are extracted.
     /// - All the key/value pairs to the right of this handle are put into a newly
@@ -1159,9 +1161,10 @@
         unsafe {
             let mut new_node = Box::new(LeafNode::new());
 
-            let (k, v, _) = self.leafy_split(&mut new_node);
+            let (k, v) = self.split_leaf_data(&mut new_node);
 
-            (self.node, k, v, Root { node: BoxedNode::from_leaf(new_node), height: 0 })
+            let right = Root { node: BoxedNode::from_leaf(new_node), height: 0 };
+            (self.node, k, v, right)
         }
     }
 
@@ -1195,29 +1198,28 @@
     /// Splits the underlying node into three parts:
     ///
     /// - The node is truncated to only contain the edges and key/value pairs to the
-    ///   right of this handle.
+    ///   left of this handle.
     /// - The key and value pointed to by this handle are extracted.
     /// - All the edges and key/value pairs to the right of this handle are put into
     ///   a newly allocated node.
     pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Internal>, K, V, Root<K, V>) {
         unsafe {
             let mut new_node = Box::new(InternalNode::new());
-
-            let (k, v, new_len) = self.leafy_split(&mut new_node.data);
-            let height = self.node.height;
-            let old_node = &*self.node.as_internal_ptr();
-
+            // Move edges out before reducing length:
+            let new_len = self.split_new_node_len();
             ptr::copy_nonoverlapping(
-                old_node.edges.as_ptr().add(self.idx + 1),
-                new_node.edges.as_mut_ptr(),
+                self.node.edge_at(self.idx + 1),
+                MaybeUninit::slice_as_mut_ptr(&mut new_node.edges),
                 new_len + 1,
             );
+            let (k, v) = self.split_leaf_data(&mut new_node.data);
 
-            let mut new_root = Root { node: BoxedNode::from_internal(new_node), height };
+            let height = self.node.height;
+            let mut right = Root { node: BoxedNode::from_internal(new_node), height };
 
-            new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len);
+            right.internal_node_as_mut().correct_childrens_parent_links(0..=new_len);
 
-            (self.node, k, v, new_root)
+            (self.node, k, v, right)
         }
     }
 
@@ -1268,8 +1270,8 @@
             if self.node.height > 1 {
                 // SAFETY: the height of the nodes being merged is one below the height
                 // of the node of this edge, thus above zero, so they are internal.
-                let mut left_node = left_node.cast_unchecked::<marker::Internal>();
-                let right_node = right_node.cast_unchecked::<marker::Internal>();
+                let mut left_node = left_node.cast_to_internal_unchecked();
+                let right_node = right_node.cast_to_internal_unchecked();
                 ptr::copy_nonoverlapping(
                     right_node.edge_at(0),
                     left_node.edges_mut().as_mut_ptr().add(left_len + 1),
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index e241697..e56fc2a 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -1,4 +1,110 @@
+use super::super::navigate;
 use super::*;
+use crate::fmt::Debug;
+use crate::string::String;
+use core::cmp::Ordering::*;
+
+impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
+    pub fn assert_back_pointers(self) {
+        match self.force() {
+            ForceResult::Leaf(_) => {}
+            ForceResult::Internal(node) => {
+                for idx in 0..=node.len() {
+                    let edge = unsafe { Handle::new_edge(node, idx) };
+                    let child = edge.descend();
+                    assert!(child.ascend().ok() == Some(edge));
+                    child.assert_back_pointers();
+                }
+            }
+        }
+    }
+
+    pub fn assert_ascending(self)
+    where
+        K: Copy + Debug + Ord,
+    {
+        struct SeriesChecker<T> {
+            previous: Option<T>,
+        }
+        impl<T: Copy + Debug + Ord> SeriesChecker<T> {
+            fn is_ascending(&mut self, next: T) {
+                if let Some(previous) = self.previous {
+                    assert!(previous < next, "{:?} >= {:?}", previous, next);
+                }
+                self.previous = Some(next);
+            }
+        }
+
+        let mut checker = SeriesChecker { previous: None };
+        self.visit_nodes_in_order(|pos| match pos {
+            navigate::Position::Leaf(node) => {
+                for idx in 0..node.len() {
+                    let key = *unsafe { node.key_at(idx) };
+                    checker.is_ascending(key);
+                }
+            }
+            navigate::Position::InternalKV(kv) => {
+                let key = *kv.into_kv().0;
+                checker.is_ascending(key);
+            }
+            navigate::Position::Internal(_) => {}
+        });
+    }
+
+    pub fn assert_and_add_lengths(self) -> usize {
+        let mut internal_length = 0;
+        let mut internal_kv_count = 0;
+        let mut leaf_length = 0;
+        self.visit_nodes_in_order(|pos| match pos {
+            navigate::Position::Leaf(node) => {
+                let is_root = self.height() == 0;
+                let min_len = if is_root { 0 } else { MIN_LEN };
+                assert!(node.len() >= min_len, "{} < {}", node.len(), min_len);
+                leaf_length += node.len();
+            }
+            navigate::Position::Internal(node) => {
+                let is_root = self.height() == node.height();
+                let min_len = if is_root { 1 } else { MIN_LEN };
+                assert!(node.len() >= min_len, "{} < {}", node.len(), min_len);
+                internal_length += node.len();
+            }
+            navigate::Position::InternalKV(_) => {
+                internal_kv_count += 1;
+            }
+        });
+        assert_eq!(internal_length, internal_kv_count);
+        let total = internal_length + leaf_length;
+        assert_eq!(self.calc_length(), total);
+        total
+    }
+
+    pub fn dump_keys(self) -> String
+    where
+        K: Debug,
+    {
+        let mut result = String::new();
+        self.visit_nodes_in_order(|pos| match pos {
+            navigate::Position::Leaf(leaf) => {
+                let depth = self.height();
+                let indent = "  ".repeat(depth);
+                result += &format!("\n{}", indent);
+                for idx in 0..leaf.len() {
+                    if idx > 0 {
+                        result += ", ";
+                    }
+                    result += &format!("{:?}", unsafe { leaf.key_at(idx) });
+                }
+            }
+            navigate::Position::Internal(_) => {}
+            navigate::Position::InternalKV(kv) => {
+                let depth = self.height() - kv.into_node().height();
+                let indent = "  ".repeat(depth);
+                result += &format!("\n{}{:?}", indent, kv.into_kv().0);
+            }
+        });
+        result
+    }
+}
 
 #[test]
 fn test_splitpoint() {
@@ -23,3 +129,44 @@
         assert!(left_len + right_len == CAPACITY);
     }
 }
+
+#[test]
+fn test_partial_cmp_eq() {
+    let mut root1: Root<i32, ()> = Root::new_leaf();
+    let mut leaf1 = unsafe { root1.leaf_node_as_mut() };
+    leaf1.push(1, ());
+    root1.push_internal_level();
+    let root2: Root<i32, ()> = Root::new_leaf();
+
+    let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type();
+    let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type();
+    let top_edge_1 = root1.node_as_ref().first_edge();
+    let top_edge_2 = root2.node_as_ref().first_edge();
+
+    assert!(leaf_edge_1a == leaf_edge_1a);
+    assert!(leaf_edge_1a != leaf_edge_1b);
+    assert!(leaf_edge_1a != top_edge_1);
+    assert!(leaf_edge_1a != top_edge_2);
+    assert!(top_edge_1 == top_edge_1);
+    assert!(top_edge_1 != top_edge_2);
+
+    assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1a), Some(Equal));
+    assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1b), Some(Less));
+    assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_1), None);
+    assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_2), None);
+    assert_eq!(top_edge_1.partial_cmp(&top_edge_1), Some(Equal));
+    assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None);
+
+    root1.pop_internal_level();
+    unsafe { root1.into_ref().deallocate_and_ascend() };
+    unsafe { root2.into_ref().deallocate_and_ascend() };
+}
+
+#[test]
+#[cfg(target_arch = "x86_64")]
+fn test_sizes() {
+    assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
+    assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 8 * 2);
+    assert_eq!(core::mem::size_of::<InternalNode<(), ()>>(), 112);
+    assert_eq!(core::mem::size_of::<InternalNode<i64, i64>>(), 112 + CAPACITY * 8 * 2);
+}
diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs
new file mode 100644
index 0000000..9733b7d
--- /dev/null
+++ b/library/alloc/src/collections/btree/remove.rs
@@ -0,0 +1,132 @@
+use super::node::{self, marker, ForceResult, Handle, NodeRef};
+use super::unwrap_unchecked;
+use core::mem;
+use core::ptr;
+
+impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
+    /// Removes a key/value-pair from the map, and returns that pair, as well as
+    /// the leaf edge corresponding to that former pair.
+    pub fn remove_kv_tracking<F: FnOnce()>(
+        self,
+        handle_emptied_internal_root: F,
+    ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
+        let (old_kv, mut pos, was_internal) = match self.force() {
+            ForceResult::Leaf(leaf) => {
+                let (old_kv, pos) = leaf.remove();
+                (old_kv, pos, false)
+            }
+            ForceResult::Internal(mut internal) => {
+                // Replace the location freed in the internal node with an
+                // adjacent KV, and remove that adjacent KV from its leaf.
+                // Always choose the adjacent KV on the left side because
+                // it is typically faster to pop an element from the end
+                // of the KV arrays without needing to shift other elements.
+
+                let key_loc = internal.kv_mut().0 as *mut K;
+                let val_loc = internal.kv_mut().1 as *mut V;
+
+                let to_remove = internal.left_edge().descend().last_leaf_edge().left_kv().ok();
+                let to_remove = unsafe { unwrap_unchecked(to_remove) };
+
+                let (kv, pos) = to_remove.remove();
+
+                let old_key = unsafe { mem::replace(&mut *key_loc, kv.0) };
+                let old_val = unsafe { mem::replace(&mut *val_loc, kv.1) };
+
+                ((old_key, old_val), pos, true)
+            }
+        };
+
+        // Handle underflow
+        let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() };
+        let mut at_leaf = true;
+        while cur_node.len() < node::MIN_LEN {
+            match handle_underfull_node(cur_node) {
+                UnderflowResult::AtRoot => break,
+                UnderflowResult::Merged(edge, merged_with_left, offset) => {
+                    // If we merged with our right sibling then our tracked
+                    // position has not changed. However if we merged with our
+                    // left sibling then our tracked position is now dangling.
+                    if at_leaf && merged_with_left {
+                        let idx = pos.idx() + offset;
+                        let node = match unsafe { ptr::read(&edge).descend().force() } {
+                            ForceResult::Leaf(leaf) => leaf,
+                            ForceResult::Internal(_) => unreachable!(),
+                        };
+                        pos = unsafe { Handle::new_edge(node, idx) };
+                    }
+
+                    let parent = edge.into_node();
+                    if parent.len() == 0 {
+                        // The parent that was just emptied must be the root,
+                        // because nodes on a lower level would not have been
+                        // left with a single child.
+                        handle_emptied_internal_root();
+                        break;
+                    } else {
+                        cur_node = parent.forget_type();
+                        at_leaf = false;
+                    }
+                }
+                UnderflowResult::Stole(stole_from_left) => {
+                    // Adjust the tracked position if we stole from a left sibling
+                    if stole_from_left && at_leaf {
+                        // SAFETY: This is safe since we just added an element to our node.
+                        unsafe {
+                            pos.move_next_unchecked();
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+
+        // If we deleted from an internal node then we need to compensate for
+        // the earlier swap and adjust the tracked position to point to the
+        // next element.
+        if was_internal {
+            pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() };
+        }
+
+        (old_kv, pos)
+    }
+}
+
+enum UnderflowResult<'a, K, V> {
+    AtRoot,
+    Merged(Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::Edge>, bool, usize),
+    Stole(bool),
+}
+
+fn handle_underfull_node<'a, K: 'a, V: 'a>(
+    node: NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>,
+) -> UnderflowResult<'_, K, V> {
+    let parent = match node.ascend() {
+        Ok(parent) => parent,
+        Err(_) => return UnderflowResult::AtRoot,
+    };
+
+    // Prefer the left KV if it exists. Merging with the left side is faster,
+    // since merging happens towards the left and `node` has fewer elements.
+    // Stealing from the left side is faster, since we can pop from the end of
+    // the KV arrays.
+    let (is_left, mut handle) = match parent.left_kv() {
+        Ok(left) => (true, left),
+        Err(parent) => {
+            let right = unsafe { unwrap_unchecked(parent.right_kv().ok()) };
+            (false, right)
+        }
+    };
+
+    if handle.can_merge() {
+        let offset = if is_left { handle.reborrow().left_edge().descend().len() + 1 } else { 0 };
+        UnderflowResult::Merged(handle.merge(), is_left, offset)
+    } else {
+        if is_left {
+            handle.steal_left();
+        } else {
+            handle.steal_right();
+        }
+        UnderflowResult::Stole(is_left)
+    }
+}
diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs
index f4e957e..9267435 100644
--- a/library/alloc/src/collections/btree/set/tests.rs
+++ b/library/alloc/src/collections/btree/set/tests.rs
@@ -1,11 +1,10 @@
-use crate::collections::BTreeSet;
+use super::super::DeterministicRng;
+use super::*;
 use crate::vec::Vec;
 use std::iter::FromIterator;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 use std::sync::atomic::{AtomicU32, Ordering};
 
-use super::super::DeterministicRng;
-
 #[test]
 fn test_clone_eq() {
     let mut m = BTreeSet::new();
@@ -528,11 +527,8 @@
     assert_eq!(s.iter().next(), None);
 }
 
-#[test]
 #[allow(dead_code)]
 fn test_variance() {
-    use std::collections::btree_set::{IntoIter, Iter, Range};
-
     fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> {
         v
     }
@@ -545,6 +541,85 @@
     fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> {
         v
     }
+    // not applied to Difference, Intersection, SymmetricDifference, Union
+}
+
+#[allow(dead_code)]
+fn test_sync() {
+    fn set<T: Sync>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v
+    }
+
+    fn iter<T: Sync>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.iter()
+    }
+
+    fn into_iter<T: Sync>(v: BTreeSet<T>) -> impl Sync {
+        v.into_iter()
+    }
+
+    fn range<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.range(..)
+    }
+
+    fn drain_filter<T: Sync + Ord>(v: &mut BTreeSet<T>) -> impl Sync + '_ {
+        v.drain_filter(|_| false)
+    }
+
+    fn difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.difference(&v)
+    }
+
+    fn intersection<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.intersection(&v)
+    }
+
+    fn symmetric_difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.symmetric_difference(&v)
+    }
+
+    fn union<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
+        v.union(&v)
+    }
+}
+
+#[allow(dead_code)]
+fn test_send() {
+    fn set<T: Send>(v: BTreeSet<T>) -> impl Send {
+        v
+    }
+
+    fn iter<T: Send + Sync>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.iter()
+    }
+
+    fn into_iter<T: Send>(v: BTreeSet<T>) -> impl Send {
+        v.into_iter()
+    }
+
+    fn range<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.range(..)
+    }
+
+    fn drain_filter<T: Send + Ord>(v: &mut BTreeSet<T>) -> impl Send + '_ {
+        v.drain_filter(|_| false)
+    }
+
+    fn difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.difference(&v)
+    }
+
+    fn intersection<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.intersection(&v)
+    }
+
+    fn symmetric_difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.symmetric_difference(&v)
+    }
+
+    fn union<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
+        v.union(&v)
+    }
 }
 
 #[test]
diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs
new file mode 100644
index 0000000..0e6e213
--- /dev/null
+++ b/library/alloc/src/collections/btree/split.rs
@@ -0,0 +1,104 @@
+use super::node::{self, ForceResult::*, Root};
+use super::search::{self, SearchResult::*};
+use core::borrow::Borrow;
+
+impl<K, V> Root<K, V> {
+    pub fn split_off<Q: ?Sized + Ord>(&mut self, right_root: &mut Self, key: &Q)
+    where
+        K: Borrow<Q>,
+    {
+        debug_assert!(right_root.height() == 0);
+        debug_assert!(right_root.node_as_ref().len() == 0);
+
+        let left_root = self;
+        for _ in 0..left_root.height() {
+            right_root.push_internal_level();
+        }
+
+        {
+            let mut left_node = left_root.node_as_mut();
+            let mut right_node = right_root.node_as_mut();
+
+            loop {
+                let mut split_edge = match search::search_node(left_node, key) {
+                    // key is going to the right tree
+                    Found(handle) => handle.left_edge(),
+                    GoDown(handle) => handle,
+                };
+
+                split_edge.move_suffix(&mut right_node);
+
+                match (split_edge.force(), right_node.force()) {
+                    (Internal(edge), Internal(node)) => {
+                        left_node = edge.descend();
+                        right_node = node.first_edge().descend();
+                    }
+                    (Leaf(_), Leaf(_)) => {
+                        break;
+                    }
+                    _ => unreachable!(),
+                }
+            }
+        }
+
+        left_root.fix_right_border();
+        right_root.fix_left_border();
+    }
+
+    /// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty.
+    fn fix_top(&mut self) {
+        while self.height() > 0 && self.node_as_ref().len() == 0 {
+            self.pop_internal_level();
+        }
+    }
+
+    fn fix_right_border(&mut self) {
+        self.fix_top();
+
+        {
+            let mut cur_node = self.node_as_mut();
+
+            while let Internal(node) = cur_node.force() {
+                let mut last_kv = node.last_kv();
+
+                if last_kv.can_merge() {
+                    cur_node = last_kv.merge().descend();
+                } else {
+                    let right_len = last_kv.reborrow().right_edge().descend().len();
+                    // `MINLEN + 1` to avoid readjust if merge happens on the next level.
+                    if right_len < node::MIN_LEN + 1 {
+                        last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len);
+                    }
+                    cur_node = last_kv.right_edge().descend();
+                }
+            }
+        }
+
+        self.fix_top();
+    }
+
+    /// The symmetric clone of `fix_right_border`.
+    fn fix_left_border(&mut self) {
+        self.fix_top();
+
+        {
+            let mut cur_node = self.node_as_mut();
+
+            while let Internal(node) = cur_node.force() {
+                let mut first_kv = node.first_kv();
+
+                if first_kv.can_merge() {
+                    cur_node = first_kv.merge().descend();
+                } else {
+                    let left_len = first_kv.reborrow().left_edge().descend().len();
+                    if left_len < node::MIN_LEN + 1 {
+                        first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len);
+                    }
+                    cur_node = first_kv.left_edge().descend();
+                }
+            }
+        }
+
+        self.fix_top();
+    }
+}
diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs
index 8e9acc4..22b02a4 100644
--- a/library/alloc/src/collections/vec_deque.rs
+++ b/library/alloc/src/collections/vec_deque.rs
@@ -9,10 +9,12 @@
 
 // ignore-tidy-filelength
 
+use core::array;
 use core::cmp::{self, Ordering};
 use core::fmt;
 use core::hash::{Hash, Hasher};
-use core::iter::{once, repeat_with, FromIterator, FusedIterator};
+use core::iter::{repeat_with, FromIterator, FusedIterator};
+use core::marker::PhantomData;
 use core::mem::{self, replace, ManuallyDrop};
 use core::ops::{Index, IndexMut, Range, RangeBounds, Try};
 use core::ptr::{self, NonNull};
@@ -99,7 +101,7 @@
     }
 
     fn remainder(self) -> impl Iterator<Item = &'b [T]> {
-        once(self.b0).chain(once(self.b1))
+        array::IntoIter::new([self.b0, self.b1])
     }
 }
 
@@ -981,7 +983,14 @@
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<'_, T> {
-        IterMut { tail: self.tail, head: self.head, ring: unsafe { self.buffer_as_mut_slice() } }
+        // SAFETY: The internal `IterMut` safety invariant is established because the
+        // `ring` we create is a dereferencable slice for lifetime '_.
+        IterMut {
+            tail: self.tail,
+            head: self.head,
+            ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()),
+            phantom: PhantomData,
+        }
     }
 
     /// Returns a pair of slices which contain, in order, the contents of the
@@ -1093,7 +1102,7 @@
     where
         R: RangeBounds<usize>,
     {
-        let Range { start, end } = slice::check_range(self.len(), range);
+        let Range { start, end } = range.assert_len(self.len());
         let tail = self.wrap_add(self.tail, start);
         let head = self.wrap_add(self.tail, end);
         (tail, head)
@@ -1169,11 +1178,14 @@
         R: RangeBounds<usize>,
     {
         let (tail, head) = self.range_tail_head(range);
+
+        // SAFETY: The internal `IterMut` safety invariant is established because the
+        // `ring` we create is a dereferencable slice for lifetime '_.
         IterMut {
             tail,
             head,
-            // The shared reference we have in &mut self is maintained in the '_ of IterMut.
-            ring: unsafe { self.buffer_as_mut_slice() },
+            ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()),
+            phantom: PhantomData,
         }
     }
 
@@ -2169,7 +2181,7 @@
     ///
     /// This method does not allocate and does not change the order of the
     /// inserted elements. As it returns a mutable slice, this can be used to
-    /// sort or binary search a deque.
+    /// sort a deque.
     ///
     /// Once the internal storage is contiguous, the [`as_slices`] and
     /// [`as_mut_slices`] methods will return the entire contents of the
@@ -2418,6 +2430,143 @@
             self.wrap_copy(self.tail, self.head, k);
         }
     }
+
+    /// Binary searches this sorted `VecDeque` for a given element.
+    ///
+    /// If the value is found then [`Result::Ok`] is returned, containing the
+    /// index of the matching element. If there are multiple matches, then any
+    /// one of the matches could be returned. If the value is not found then
+    /// [`Result::Err`] is returned, containing the index where a matching
+    /// element could be inserted while maintaining sorted order.
+    ///
+    /// # Examples
+    ///
+    /// Looks up a series of four elements. The first is found, with a
+    /// uniquely determined position; the second and third are not
+    /// found; the fourth could match any position in `[1, 4]`.
+    ///
+    /// ```
+    /// #![feature(vecdeque_binary_search)]
+    /// use std::collections::VecDeque;
+    ///
+    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+    ///
+    /// assert_eq!(deque.binary_search(&13),  Ok(9));
+    /// assert_eq!(deque.binary_search(&4),   Err(7));
+    /// assert_eq!(deque.binary_search(&100), Err(13));
+    /// let r = deque.binary_search(&1);
+    /// assert!(matches!(r, Ok(1..=4)));
+    /// ```
+    ///
+    /// If you want to insert an item to a sorted `VecDeque`, while maintaining
+    /// sort order:
+    ///
+    /// ```
+    /// #![feature(vecdeque_binary_search)]
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+    /// let num = 42;
+    /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x);
+    /// deque.insert(idx, num);
+    /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+    /// ```
+    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[inline]
+    pub fn binary_search(&self, x: &T) -> Result<usize, usize>
+    where
+        T: Ord,
+    {
+        self.binary_search_by(|e| e.cmp(x))
+    }
+
+    /// Binary searches this sorted `VecDeque` with a comparator function.
+    ///
+    /// The comparator function should implement an order consistent
+    /// with the sort order of the underlying `VecDeque`, returning an
+    /// order code that indicates whether its argument is `Less`,
+    /// `Equal` or `Greater` than the desired target.
+    ///
+    /// If the value is found then [`Result::Ok`] is returned, containing the
+    /// index of the matching element. If there are multiple matches, then any
+    /// one of the matches could be returned. If the value is not found then
+    /// [`Result::Err`] is returned, containing the index where a matching
+    /// element could be inserted while maintaining sorted order.
+    ///
+    /// # Examples
+    ///
+    /// Looks up a series of four elements. The first is found, with a
+    /// uniquely determined position; the second and third are not
+    /// found; the fourth could match any position in `[1, 4]`.
+    ///
+    /// ```
+    /// #![feature(vecdeque_binary_search)]
+    /// use std::collections::VecDeque;
+    ///
+    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+    ///
+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)),  Ok(9));
+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)),   Err(7));
+    /// assert_eq!(deque.binary_search_by(|x| x.cmp(&100)), Err(13));
+    /// let r = deque.binary_search_by(|x| x.cmp(&1));
+    /// assert!(matches!(r, Ok(1..=4)));
+    /// ```
+    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
+    where
+        F: FnMut(&'a T) -> Ordering,
+    {
+        let (front, back) = self.as_slices();
+
+        if let Some(Ordering::Less | Ordering::Equal) = back.first().map(|elem| f(elem)) {
+            back.binary_search_by(f).map(|idx| idx + front.len()).map_err(|idx| idx + front.len())
+        } else {
+            front.binary_search_by(f)
+        }
+    }
+
+    /// Binary searches this sorted `VecDeque` with a key extraction function.
+    ///
+    /// Assumes that the `VecDeque` is sorted by the key, for instance with
+    /// [`make_contiguous().sort_by_key()`](#method.make_contiguous) using the same
+    /// key extraction function.
+    ///
+    /// If the value is found then [`Result::Ok`] is returned, containing the
+    /// index of the matching element. If there are multiple matches, then any
+    /// one of the matches could be returned. If the value is not found then
+    /// [`Result::Err`] is returned, containing the index where a matching
+    /// element could be inserted while maintaining sorted order.
+    ///
+    /// # Examples
+    ///
+    /// Looks up a series of four elements in a slice of pairs sorted by
+    /// their second elements. The first is found, with a uniquely
+    /// determined position; the second and third are not found; the
+    /// fourth could match any position in `[1, 4]`.
+    ///
+    /// ```
+    /// #![feature(vecdeque_binary_search)]
+    /// use std::collections::VecDeque;
+    ///
+    /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1),
+    ///          (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
+    ///          (1, 21), (2, 34), (4, 55)].into();
+    ///
+    /// assert_eq!(deque.binary_search_by_key(&13, |&(a,b)| b),  Ok(9));
+    /// assert_eq!(deque.binary_search_by_key(&4, |&(a,b)| b),   Err(7));
+    /// assert_eq!(deque.binary_search_by_key(&100, |&(a,b)| b), Err(13));
+    /// let r = deque.binary_search_by_key(&1, |&(a,b)| b);
+    /// assert!(matches!(r, Ok(1..=4)));
+    /// ```
+    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[inline]
+    pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
+    where
+        F: FnMut(&'a T) -> B,
+        B: Ord,
+    {
+        self.binary_search_by(|k| f(k).cmp(b))
+    }
 }
 
 impl<T: Clone> VecDeque<T> {
@@ -2492,6 +2641,25 @@
     }
 }
 
+impl<T> RingSlices for *mut [T] {
+    fn slice(self, from: usize, to: usize) -> Self {
+        assert!(from <= to && to < self.len());
+        // Not using `get_unchecked_mut` to keep this a safe operation.
+        let len = to - from;
+        ptr::slice_from_raw_parts_mut(self.as_mut_ptr().wrapping_add(from), len)
+    }
+
+    fn split_at(self, mid: usize) -> (Self, Self) {
+        let len = self.len();
+        let ptr = self.as_mut_ptr();
+        assert!(mid <= len);
+        (
+            ptr::slice_from_raw_parts_mut(ptr, mid),
+            ptr::slice_from_raw_parts_mut(ptr.wrapping_add(mid), len - mid),
+        )
+    }
+}
+
 /// Calculate the number of elements left to be read in the buffer
 #[inline]
 fn count(tail: usize, head: usize, size: usize) -> usize {
@@ -2661,15 +2829,27 @@
 /// [`iter_mut`]: VecDeque::iter_mut
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> {
-    ring: &'a mut [T],
+    // Internal safety invariant: the entire slice is dereferencable.
+    ring: *mut [T],
     tail: usize,
     head: usize,
+    phantom: PhantomData<&'a mut [T]>,
 }
 
+// SAFETY: we do nothing thread-local and there is no interior mutability,
+// so the usual structural `Send`/`Sync` apply.
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send> Send for IterMut<'_, T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
+
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let (front, back) = RingSlices::ring_slices(&*self.ring, self.head, self.tail);
+        let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
+        // SAFETY: these are the elements we have not handed out yet, so aliasing is fine.
+        // The `IterMut` invariant also ensures everything is dereferencable.
+        let (front, back) = unsafe { (&*front, &*back) };
         f.debug_tuple("IterMut").field(&front).field(&back).finish()
     }
 }
@@ -2688,7 +2868,7 @@
 
         unsafe {
             let elem = self.ring.get_unchecked_mut(tail);
-            Some(&mut *(elem as *mut _))
+            Some(&mut *elem)
         }
     }
 
@@ -2703,6 +2883,9 @@
         F: FnMut(Acc, Self::Item) -> Acc,
     {
         let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
+        // SAFETY: these are the elements we have not handed out yet, so aliasing is fine.
+        // The `IterMut` invariant also ensures everything is dereferencable.
+        let (front, back) = unsafe { (&mut *front, &mut *back) };
         accum = front.iter_mut().fold(accum, &mut f);
         back.iter_mut().fold(accum, &mut f)
     }
@@ -2734,7 +2917,7 @@
 
         unsafe {
             let elem = self.ring.get_unchecked_mut(self.head);
-            Some(&mut *(elem as *mut _))
+            Some(&mut *elem)
         }
     }
 
@@ -2743,6 +2926,9 @@
         F: FnMut(Acc, Self::Item) -> Acc,
     {
         let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
+        // SAFETY: these are the elements we have not handed out yet, so aliasing is fine.
+        // The `IterMut` invariant also ensures everything is dereferencable.
+        let (front, back) = unsafe { (&mut *front, &mut *back) };
         accum = back.iter_mut().rfold(accum, &mut f);
         front.iter_mut().rfold(accum, &mut f)
     }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index b33cb3a..b69e190 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -77,6 +77,7 @@
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(allocator_api)]
 #![feature(array_chunks)]
+#![feature(array_value_iter)]
 #![feature(array_windows)]
 #![feature(allow_internal_unstable)]
 #![feature(arbitrary_self_types)]
@@ -113,11 +114,11 @@
 #![feature(or_patterns)]
 #![feature(pattern)]
 #![feature(ptr_internals)]
+#![feature(range_bounds_assert_len)]
 #![feature(raw_ref_op)]
 #![feature(rustc_attrs)]
 #![feature(receiver_trait)]
 #![feature(min_specialization)]
-#![feature(slice_check_range)]
 #![feature(slice_ptr_get)]
 #![feature(slice_ptr_len)]
 #![feature(staged_api)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 1844d3a..7c834f0 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -259,7 +259,7 @@
     /// Ensures that the buffer contains at least enough space to hold `len +
     /// additional` elements. If it doesn't already have enough capacity, will
     /// reallocate enough space plus comfortable slack space to get amortized
-    /// `O(1)` behavior. Will limit this behavior if it would needlessly cause
+    /// *O*(1) behavior. Will limit this behavior if it would needlessly cause
     /// itself to panic.
     ///
     /// If `len` exceeds `self.capacity()`, this may fail to actually allocate
diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs
index e4c8b37..cb4fe1b 100644
--- a/library/alloc/src/raw_vec/tests.rs
+++ b/library/alloc/src/raw_vec/tests.rs
@@ -3,7 +3,7 @@
 
 #[test]
 fn allocator_param() {
-    use crate::alloc::AllocErr;
+    use crate::alloc::AllocError;
 
     // Writing a test of integration between third-party
     // allocators and `RawVec` is a little tricky because the `RawVec`
@@ -21,10 +21,10 @@
         fuel: Cell<usize>,
     }
     unsafe impl AllocRef for BoundedAlloc {
-        fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+        fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
             let size = layout.size();
             if size > self.fuel.get() {
-                return Err(AllocErr);
+                return Err(AllocError);
             }
             match Global.alloc(layout) {
                 ok @ Ok(_) => {
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index f998e49..939ebe0 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -247,7 +247,7 @@
 use core::ptr::{self, NonNull};
 use core::slice::from_raw_parts_mut;
 
-use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout};
+use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 use crate::string::String;
 use crate::vec::Vec;
@@ -996,7 +996,7 @@
     /// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
     unsafe fn allocate_for_layout(
         value_layout: Layout,
-        allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocErr>,
+        allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
         mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>,
     ) -> *mut RcBox<T> {
         // Calculate layout using the given value layout.
@@ -1721,7 +1721,21 @@
     pub fn new() -> Weak<T> {
         Weak { ptr: NonNull::new(usize::MAX as *mut RcBox<T>).expect("MAX is not 0") }
     }
+}
 
+pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
+    let address = ptr.as_ptr() as *mut () as usize;
+    address == usize::MAX
+}
+
+/// Helper type to allow accessing the reference counts without
+/// making any assertions about the data field.
+struct WeakInner<'a> {
+    weak: &'a Cell<usize>,
+    strong: &'a Cell<usize>,
+}
+
+impl<T: ?Sized> Weak<T> {
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1841,33 +1855,20 @@
     /// [`new`]: Weak::new
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
-        if ptr.is_null() {
-            Self::new()
-        } else {
-            // See Rc::from_raw for details
-            unsafe {
-                let offset = data_offset(ptr);
-                let fake_ptr = ptr as *mut RcBox<T>;
-                let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
-                Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
-            }
-        }
+        // SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
+        // See Weak::as_ptr for context on how the input pointer is derived.
+        let offset = unsafe { data_offset(ptr) };
+
+        // Reverse the offset to find the original RcBox.
+        // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized).
+        let ptr = unsafe {
+            set_data_ptr(ptr as *mut RcBox<T>, (ptr as *mut u8).wrapping_offset(-offset))
+        };
+
+        // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
+        Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } }
     }
-}
 
-pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
-    let address = ptr.as_ptr() as *mut () as usize;
-    address == usize::MAX
-}
-
-/// Helper type to allow accessing the reference counts without
-/// making any assertions about the data field.
-struct WeakInner<'a> {
-    weak: &'a Cell<usize>,
-    strong: &'a Cell<usize>,
-}
-
-impl<T: ?Sized> Weak<T> {
     /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
     /// dropping of the inner value if successful.
     ///
diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs
index fed48a5..bb5c3f4 100644
--- a/library/alloc/src/rc/tests.rs
+++ b/library/alloc/src/rc/tests.rs
@@ -191,6 +191,48 @@
 }
 
 #[test]
+fn into_from_weak_raw() {
+    let x = Rc::new(box "hello");
+    let y = Rc::downgrade(&x);
+
+    let y_ptr = Weak::into_raw(y);
+    unsafe {
+        assert_eq!(**y_ptr, "hello");
+
+        let y = Weak::from_raw(y_ptr);
+        let y_up = Weak::upgrade(&y).unwrap();
+        assert_eq!(**y_up, "hello");
+        drop(y_up);
+
+        assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello"));
+    }
+}
+
+#[test]
+fn test_into_from_weak_raw_unsized() {
+    use std::fmt::Display;
+    use std::string::ToString;
+
+    let arc: Rc<str> = Rc::from("foo");
+    let weak: Weak<str> = Rc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }, "foo");
+    assert!(weak.ptr_eq(&weak2));
+
+    let arc: Rc<dyn Display> = Rc::new(123);
+    let weak: Weak<dyn Display> = Rc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }.to_string(), "123");
+    assert!(weak.ptr_eq(&weak2));
+}
+
+#[test]
 fn get_mut() {
     let mut x = Rc::new(3);
     *Rc::get_mut(&mut x).unwrap() = 4;
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index 79403cf..3db6696 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -91,8 +91,6 @@
 use crate::boxed::Box;
 use crate::vec::Vec;
 
-#[unstable(feature = "slice_check_range", issue = "76393")]
-pub use core::slice::check_range;
 #[unstable(feature = "array_chunks", issue = "74985")]
 pub use core::slice::ArrayChunks;
 #[unstable(feature = "array_chunks", issue = "74985")]
@@ -169,7 +167,7 @@
 impl<T> [T] {
     /// Sorts the slice.
     ///
-    /// This sort is stable (i.e., does not reorder equal elements) and `O(n * log(n))` worst-case.
+    /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case.
     ///
     /// When applicable, unstable sorting is preferred because it is generally faster than stable
     /// sorting and it doesn't allocate auxiliary memory.
@@ -204,7 +202,7 @@
 
     /// Sorts the slice with a comparator function.
     ///
-    /// This sort is stable (i.e., does not reorder equal elements) and `O(n * log(n))` worst-case.
+    /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case.
     ///
     /// The comparator function must define a total ordering for the elements in the slice. If
     /// the ordering is not total, the order of the elements is unspecified. An order is a
@@ -258,8 +256,8 @@
 
     /// Sorts the slice with a key extraction function.
     ///
-    /// This sort is stable (i.e., does not reorder equal elements) and `O(m * n * log(n))`
-    /// worst-case, where the key function is `O(m)`.
+    /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*))
+    /// worst-case, where the key function is *O*(*m*).
     ///
     /// For expensive key functions (e.g. functions that are not simple property accesses or
     /// basic operations), [`sort_by_cached_key`](#method.sort_by_cached_key) is likely to be
@@ -301,8 +299,8 @@
     ///
     /// During sorting, the key function is called only once per element.
     ///
-    /// This sort is stable (i.e., does not reorder equal elements) and `O(m * n + n * log(n))`
-    /// worst-case, where the key function is `O(m)`.
+    /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* log(*n*))
+    /// worst-case, where the key function is *O*(*m*).
     ///
     /// For simple key functions (e.g., functions that are property accesses or
     /// basic operations), [`sort_by_key`](#method.sort_by_key) is likely to be
@@ -946,7 +944,7 @@
 /// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len`
 /// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len`
 ///
-/// The invariants ensure that the total running time is `O(n * log(n))` worst-case.
+/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case.
 fn merge_sort<T, F>(v: &mut [T], mut is_less: F)
 where
     F: FnMut(&T, &T) -> bool,
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index d3598cc..72ed036 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1,8 +1,8 @@
-//! A UTF-8 encoded, growable string.
+//! A UTF-8–encoded, growable string.
 //!
-//! This module contains the [`String`] type, a trait for converting
-//! [`ToString`]s, and several error types that may result from working with
-//! [`String`]s.
+//! This module contains the [`String`] type, the [`ToString`] trait for
+//! converting to strings, and several error types that may result from
+//! working with [`String`]s.
 //!
 //! # Examples
 //!
@@ -49,7 +49,6 @@
 use core::ops::Bound::{Excluded, Included, Unbounded};
 use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
 use core::ptr;
-use core::slice;
 use core::str::{lossy, pattern::Pattern};
 
 use crate::borrow::{Cow, ToOwned};
@@ -58,7 +57,7 @@
 use crate::str::{self, from_boxed_utf8_unchecked, Chars, FromStr, Utf8Error};
 use crate::vec::Vec;
 
-/// A UTF-8 encoded, growable string.
+/// A UTF-8–encoded, growable string.
 ///
 /// The `String` type is the most common string type that has ownership over the
 /// contents of the string. It has a close relationship with its borrowed
@@ -566,7 +565,7 @@
         Cow::Owned(res)
     }
 
-    /// Decode a UTF-16 encoded vector `v` into a `String`, returning [`Err`]
+    /// Decode a UTF-16–encoded vector `v` into a `String`, returning [`Err`]
     /// if `v` contains any invalid data.
     ///
     /// # Examples
@@ -600,7 +599,7 @@
         Ok(ret)
     }
 
-    /// Decode a UTF-16 encoded slice `v` into a `String`, replacing
+    /// Decode a UTF-16–encoded slice `v` into a `String`, replacing
     /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD].
     ///
     /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`],
@@ -1507,14 +1506,14 @@
         // of the vector version. The data is just plain bytes.
         // Because the range removal happens in Drop, if the Drain iterator is leaked,
         // the removal will not happen.
-        let Range { start, end } = slice::check_range(self.len(), range);
+        let Range { start, end } = range.assert_len(self.len());
         assert!(self.is_char_boundary(start));
         assert!(self.is_char_boundary(end));
 
         // Take out two simultaneous borrows. The &mut String won't be accessed
         // until iteration is over, in Drop.
         let self_ptr = self as *mut _;
-        // SAFETY: `check_range` and `is_char_boundary` do the appropriate bounds checks.
+        // SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks.
         let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
 
         Drain { start, end, iter: chars_iter, string: self_ptr }
@@ -2192,15 +2191,15 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: fmt::Display + ?Sized> ToString for T {
     // A common guideline is to not inline generic functions. However,
-    // remove `#[inline]` from this method causes non-negligible regression.
-    // See <https://github.com/rust-lang/rust/pull/74852> as last attempt try to remove it.
+    // removing `#[inline]` from this method causes non-negligible regressions.
+    // See <https://github.com/rust-lang/rust/pull/74852>, the last attempt
+    // to try to remove it.
     #[inline]
     default fn to_string(&self) -> String {
         use fmt::Write;
         let mut buf = String::new();
         buf.write_fmt(format_args!("{}", self))
             .expect("a Display implementation returned an error unexpectedly");
-        buf.shrink_to_fit();
         buf
     }
 }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 6a240fb..3a83aa7 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -21,7 +21,7 @@
 use core::sync::atomic;
 use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
 
-use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout};
+use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::rc::is_dangling;
@@ -969,7 +969,7 @@
     /// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
     unsafe fn allocate_for_layout(
         value_layout: Layout,
-        allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocErr>,
+        allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
         mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>,
     ) -> *mut ArcInner<T> {
         // Calculate layout using the given value layout.
@@ -1509,7 +1509,16 @@
     pub fn new() -> Weak<T> {
         Weak { ptr: NonNull::new(usize::MAX as *mut ArcInner<T>).expect("MAX is not 0") }
     }
+}
 
+/// Helper type to allow accessing the reference counts without
+/// making any assertions about the data field.
+struct WeakInner<'a> {
+    weak: &'a atomic::AtomicUsize,
+    strong: &'a atomic::AtomicUsize,
+}
+
+impl<T: ?Sized> Weak<T> {
     /// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
     ///
     /// The pointer is valid only if there are some strong references. The pointer may be dangling,
@@ -1629,28 +1638,20 @@
     /// [`forget`]: std::mem::forget
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
-        if ptr.is_null() {
-            Self::new()
-        } else {
-            // See Arc::from_raw for details
-            unsafe {
-                let offset = data_offset(ptr);
-                let fake_ptr = ptr as *mut ArcInner<T>;
-                let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
-                Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") }
-            }
-        }
+        // SAFETY: data_offset is safe to call, because this pointer originates from a Weak.
+        // See Weak::as_ptr for context on how the input pointer is derived.
+        let offset = unsafe { data_offset(ptr) };
+
+        // Reverse the offset to find the original ArcInner.
+        // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized)
+        let ptr = unsafe {
+            set_data_ptr(ptr as *mut ArcInner<T>, (ptr as *mut u8).wrapping_offset(-offset))
+        };
+
+        // SAFETY: we now have recovered the original Weak pointer, so can create the Weak.
+        unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } }
     }
-}
 
-/// Helper type to allow accessing the reference counts without
-/// making any assertions about the data field.
-struct WeakInner<'a> {
-    weak: &'a atomic::AtomicUsize,
-    strong: &'a atomic::AtomicUsize,
-}
-
-impl<T: ?Sized> Weak<T> {
     /// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying
     /// dropping of the inner value if successful.
     ///
diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs
index d251717..77f328d 100644
--- a/library/alloc/src/sync/tests.rs
+++ b/library/alloc/src/sync/tests.rs
@@ -141,6 +141,48 @@
 }
 
 #[test]
+fn into_from_weak_raw() {
+    let x = Arc::new(box "hello");
+    let y = Arc::downgrade(&x);
+
+    let y_ptr = Weak::into_raw(y);
+    unsafe {
+        assert_eq!(**y_ptr, "hello");
+
+        let y = Weak::from_raw(y_ptr);
+        let y_up = Weak::upgrade(&y).unwrap();
+        assert_eq!(**y_up, "hello");
+        drop(y_up);
+
+        assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello"));
+    }
+}
+
+#[test]
+fn test_into_from_weak_raw_unsized() {
+    use std::fmt::Display;
+    use std::string::ToString;
+
+    let arc: Arc<str> = Arc::from("foo");
+    let weak: Weak<str> = Arc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }, "foo");
+    assert!(weak.ptr_eq(&weak2));
+
+    let arc: Arc<dyn Display> = Arc::new(123);
+    let weak: Weak<dyn Display> = Arc::downgrade(&arc);
+
+    let ptr = Weak::into_raw(weak.clone());
+    let weak2 = unsafe { Weak::from_raw(ptr) };
+
+    assert_eq!(unsafe { &*ptr }.to_string(), "123");
+    assert!(weak.ptr_eq(&weak2));
+}
+
+#[test]
 fn test_cowarc_clone_make_mut() {
     let mut cow0 = Arc::new(75);
     let mut cow1 = cow0.clone();
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs
index fec4c1e..5b3604d 100644
--- a/library/alloc/src/vec.rs
+++ b/library/alloc/src/vec.rs
@@ -259,7 +259,7 @@
 /// `Vec` does not guarantee any particular growth strategy when reallocating
 /// when full, nor when [`reserve`] is called. The current strategy is basic
 /// and it may prove desirable to use a non-constant growth factor. Whatever
-/// strategy is used will of course guarantee `O(1)` amortized [`push`].
+/// strategy is used will of course guarantee *O*(1) amortized [`push`].
 ///
 /// `vec![x; n]`, `vec![a, b, c, d]`, and
 /// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
@@ -567,9 +567,10 @@
         self.buf.try_reserve(self.len, additional)
     }
 
-    /// Tries to reserves the minimum capacity for exactly `additional` more elements to
-    /// be inserted in the given `Vec<T>`. After calling `try_reserve_exact`,
-    /// capacity will be greater than or equal to `self.len() + additional`.
+    /// Tries to reserve the minimum capacity for exactly `additional`
+    /// elements to be inserted in the given `Vec<T>`. After calling
+    /// `try_reserve_exact`, capacity will be greater than or equal to
+    /// `self.len() + additional` if it returns `Ok(())`.
     /// Does nothing if the capacity is already sufficient.
     ///
     /// Note that the allocator may give the collection more space than it
@@ -1313,7 +1314,7 @@
         // the hole, and the vector length is restored to the new length.
         //
         let len = self.len();
-        let Range { start, end } = slice::check_range(len, range);
+        let Range { start, end } = range.assert_len(len);
 
         unsafe {
             // set self.vec length's to start, to be safe in case Drain is leaked
@@ -1475,7 +1476,8 @@
     /// `'a`. If the type has only static references, or none at all, then this
     /// may be chosen to be `'static`.
     ///
-    /// This function is similar to the `leak` function on `Box`.
+    /// This function is similar to the [`leak`][Box::leak] function on [`Box`]
+    /// except that there is no way to recover the leaked memory.
     ///
     /// This function is mainly useful for data that lives for the remainder of
     /// the program's life. Dropping the returned reference will cause a memory
@@ -1601,50 +1603,6 @@
     }
 }
 
-impl<T: Default> Vec<T> {
-    /// Resizes the `Vec` in-place so that `len` is equal to `new_len`.
-    ///
-    /// If `new_len` is greater than `len`, the `Vec` is extended by the
-    /// difference, with each additional slot filled with [`Default::default()`].
-    /// If `new_len` is less than `len`, the `Vec` is simply truncated.
-    ///
-    /// This method uses [`Default`] to create new values on every push. If
-    /// you'd rather [`Clone`] a given value, use [`resize`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![allow(deprecated)]
-    /// #![feature(vec_resize_default)]
-    ///
-    /// let mut vec = vec![1, 2, 3];
-    /// vec.resize_default(5);
-    /// assert_eq!(vec, [1, 2, 3, 0, 0]);
-    ///
-    /// let mut vec = vec![1, 2, 3, 4];
-    /// vec.resize_default(2);
-    /// assert_eq!(vec, [1, 2]);
-    /// ```
-    ///
-    /// [`resize`]: Vec::resize
-    #[unstable(feature = "vec_resize_default", issue = "41758")]
-    #[rustc_deprecated(
-        reason = "This is moving towards being removed in favor \
-                  of `.resize_with(Default::default)`.  If you disagree, please comment \
-                  in the tracking issue.",
-        since = "1.33.0"
-    )]
-    pub fn resize_default(&mut self, new_len: usize) {
-        let len = self.len();
-
-        if new_len > len {
-            self.extend_with(new_len - len, ExtendDefault);
-        } else {
-            self.truncate(new_len);
-        }
-    }
-}
-
 // This code generalizes `extend_with_{element,default}`.
 trait ExtendWith<T> {
     fn next(&mut self) -> T;
@@ -2281,14 +2239,14 @@
 
         // use try-fold since
         // - it vectorizes better for some iterator adapters
-        // - unlike most internal iteration methods methods it only takes a &mut self
+        // - unlike most internal iteration methods, it only takes a &mut self
         // - 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 = iterator
             .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
             .unwrap();
         // iteration succeeded, don't drop head
-        let dst = mem::ManuallyDrop::new(sink).dst;
+        let dst = ManuallyDrop::new(sink).dst;
 
         let src = unsafe { iterator.as_inner().as_into_iter() };
         // check if SourceIter contract was upheld
@@ -2590,6 +2548,8 @@
 __impl_slice_eq1! { [] Vec<A>, &mut [B], #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [] &[A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
 __impl_slice_eq1! { [] &mut [A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [] Vec<A>, [B], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
+__impl_slice_eq1! { [] [A], Vec<B>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
 __impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B> where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [] Cow<'_, [A]>, &[B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index 851ca17..6a83f5d 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -1,3 +1,4 @@
+use std::cell::Cell;
 use std::mem::MaybeUninit;
 use std::ptr::NonNull;
 
@@ -49,3 +50,10 @@
         assert_eq!(copy.as_ptr() as usize, copy_raw);
     }
 }
+
+#[test]
+fn box_deref_lval() {
+    let x = Box::new(Cell::new(5));
+    x.set(1000);
+    assert_eq!(x.get(), 1000);
+}
diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs
index 0ad092b..757fddd 100644
--- a/library/alloc/tests/fmt.rs
+++ b/library/alloc/tests/fmt.rs
@@ -1,7 +1,327 @@
-use std::fmt;
+#![deny(warnings)]
+
+use std::cell::RefCell;
+use std::fmt::{self, Write};
 
 #[test]
 fn test_format() {
     let s = fmt::format(format_args!("Hello, {}!", "world"));
     assert_eq!(s, "Hello, world!");
 }
+
+struct A;
+struct B;
+struct C;
+struct D;
+
+impl fmt::LowerHex for A {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("aloha")
+    }
+}
+impl fmt::UpperHex for B {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("adios")
+    }
+}
+impl fmt::Display for C {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad_integral(true, "☃", "123")
+    }
+}
+impl fmt::Binary for D {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("aa")?;
+        f.write_char('☃')?;
+        f.write_str("bb")
+    }
+}
+
+macro_rules! t {
+    ($a:expr, $b:expr) => {
+        assert_eq!($a, $b)
+    };
+}
+
+#[test]
+fn test_format_macro_interface() {
+    // Various edge cases without formats
+    t!(format!(""), "");
+    t!(format!("hello"), "hello");
+    t!(format!("hello {{"), "hello {");
+
+    // default formatters should work
+    t!(format!("{}", 1.0f32), "1");
+    t!(format!("{}", 1.0f64), "1");
+    t!(format!("{}", "a"), "a");
+    t!(format!("{}", "a".to_string()), "a");
+    t!(format!("{}", false), "false");
+    t!(format!("{}", 'a'), "a");
+
+    // At least exercise all the formats
+    t!(format!("{}", true), "true");
+    t!(format!("{}", '☃'), "☃");
+    t!(format!("{}", 10), "10");
+    t!(format!("{}", 10_usize), "10");
+    t!(format!("{:?}", '☃'), "'☃'");
+    t!(format!("{:?}", 10), "10");
+    t!(format!("{:?}", 10_usize), "10");
+    t!(format!("{:?}", "true"), "\"true\"");
+    t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
+    t!(
+        format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
+        r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#
+    );
+    t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\u{0}bar\u{1}baz\u{7f}qux""#);
+    t!(format!("{:o}", 10_usize), "12");
+    t!(format!("{:x}", 10_usize), "a");
+    t!(format!("{:X}", 10_usize), "A");
+    t!(format!("{}", "foo"), "foo");
+    t!(format!("{}", "foo".to_string()), "foo");
+    if cfg!(target_pointer_width = "32") {
+        t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
+        t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
+    } else {
+        t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
+        t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
+    }
+    t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
+    t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
+    t!(format!("{:x}", A), "aloha");
+    t!(format!("{:X}", B), "adios");
+    t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
+    t!(format!("{1} {0}", 0, 1), "1 0");
+    t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1");
+    t!(format!("{foo} {1} {bar} {0}", 0, 1, foo = 2, bar = 3), "2 1 3 0");
+    t!(format!("{} {0}", "a"), "a a");
+    t!(format!("{_foo}", _foo = 6usize), "6");
+    t!(format!("{foo_bar}", foo_bar = 1), "1");
+    t!(format!("{}", 5 + 5), "10");
+    t!(format!("{:#4}", C), "☃123");
+    t!(format!("{:b}", D), "aa☃bb");
+
+    let a: &dyn fmt::Debug = &1;
+    t!(format!("{:?}", a), "1");
+
+    // Formatting strings and their arguments
+    t!(format!("{}", "a"), "a");
+    t!(format!("{:4}", "a"), "a   ");
+    t!(format!("{:4}", "☃"), "☃   ");
+    t!(format!("{:>4}", "a"), "   a");
+    t!(format!("{:<4}", "a"), "a   ");
+    t!(format!("{:^5}", "a"), "  a  ");
+    t!(format!("{:^5}", "aa"), " aa  ");
+    t!(format!("{:^4}", "a"), " a  ");
+    t!(format!("{:^4}", "aa"), " aa ");
+    t!(format!("{:.4}", "a"), "a");
+    t!(format!("{:4.4}", "a"), "a   ");
+    t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "      aaaa");
+    t!(format!("{:2.4}", "aaaaa"), "aaaa");
+    t!(format!("{:2.4}", "aaaa"), "aaaa");
+    t!(format!("{:2.4}", "aaa"), "aaa");
+    t!(format!("{:2.4}", "aa"), "aa");
+    t!(format!("{:2.4}", "a"), "a ");
+    t!(format!("{:0>2}", "a"), "0a");
+    t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
+    t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
+    t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4), "aaaa");
+    t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4), "aaaa");
+    t!(format!("{:1$}", "a", 4), "a   ");
+    t!(format!("{1:0$}", 4, "a"), "a   ");
+    t!(format!("{:a$}", "a", a = 4), "a   ");
+    t!(format!("{:-#}", "a"), "a");
+    t!(format!("{:+#}", "a"), "a");
+    t!(format!("{:/^10.8}", "1234567890"), "/12345678/");
+
+    // Some float stuff
+    t!(format!("{:}", 1.0f32), "1");
+    t!(format!("{:}", 1.0f64), "1");
+    t!(format!("{:.3}", 1.0f64), "1.000");
+    t!(format!("{:10.3}", 1.0f64), "     1.000");
+    t!(format!("{:+10.3}", 1.0f64), "    +1.000");
+    t!(format!("{:+10.3}", -1.0f64), "    -1.000");
+
+    t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
+    t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
+    t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
+    t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
+    t!(format!("{:10.3e}", 1.2345e6f64), "   1.234e6");
+    t!(format!("{:+10.3e}", 1.2345e6f64), "  +1.234e6");
+    t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");
+
+    // Float edge cases
+    t!(format!("{}", -0.0), "0");
+    t!(format!("{:?}", -0.0), "-0.0");
+    t!(format!("{:?}", 0.0), "0.0");
+
+    // sign aware zero padding
+    t!(format!("{:<3}", 1), "1  ");
+    t!(format!("{:>3}", 1), "  1");
+    t!(format!("{:^3}", 1), " 1 ");
+    t!(format!("{:03}", 1), "001");
+    t!(format!("{:<03}", 1), "001");
+    t!(format!("{:>03}", 1), "001");
+    t!(format!("{:^03}", 1), "001");
+    t!(format!("{:+03}", 1), "+01");
+    t!(format!("{:<+03}", 1), "+01");
+    t!(format!("{:>+03}", 1), "+01");
+    t!(format!("{:^+03}", 1), "+01");
+    t!(format!("{:#05x}", 1), "0x001");
+    t!(format!("{:<#05x}", 1), "0x001");
+    t!(format!("{:>#05x}", 1), "0x001");
+    t!(format!("{:^#05x}", 1), "0x001");
+    t!(format!("{:05}", 1.2), "001.2");
+    t!(format!("{:<05}", 1.2), "001.2");
+    t!(format!("{:>05}", 1.2), "001.2");
+    t!(format!("{:^05}", 1.2), "001.2");
+    t!(format!("{:05}", -1.2), "-01.2");
+    t!(format!("{:<05}", -1.2), "-01.2");
+    t!(format!("{:>05}", -1.2), "-01.2");
+    t!(format!("{:^05}", -1.2), "-01.2");
+    t!(format!("{:+05}", 1.2), "+01.2");
+    t!(format!("{:<+05}", 1.2), "+01.2");
+    t!(format!("{:>+05}", 1.2), "+01.2");
+    t!(format!("{:^+05}", 1.2), "+01.2");
+
+    // Ergonomic format_args!
+    t!(format!("{0:x} {0:X}", 15), "f F");
+    t!(format!("{0:x} {0:X} {}", 15), "f F 15");
+    t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a = 15), "dDfEeF");
+    t!(format!("{a:x} {a:X}", a = 15), "f F");
+
+    // And its edge cases
+    t!(
+        format!(
+            "{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}",
+            4,
+            a = "abcdefg",
+            b = "hijklmn",
+            c = 3
+        ),
+        "abcd hijk 4\nabc hij 3"
+    );
+    t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a = "abcdef"), "abcd 4 efg");
+    t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a = 2), "aa 2 0x2");
+
+    // Test that pointers don't get truncated.
+    {
+        let val = usize::MAX;
+        let exp = format!("{:#x}", val);
+        t!(format!("{:p}", val as *const isize), exp);
+    }
+
+    // Escaping
+    t!(format!("{{"), "{");
+    t!(format!("}}"), "}");
+
+    // make sure that format! doesn't move out of local variables
+    let a = Box::new(3);
+    format!("{}", a);
+    format!("{}", a);
+
+    // make sure that format! doesn't cause spurious unused-unsafe warnings when
+    // it's inside of an outer unsafe block
+    unsafe {
+        let a: isize = ::std::mem::transmute(3_usize);
+        format!("{}", a);
+    }
+
+    // test that trailing commas are acceptable
+    format!("{}", "test",);
+    format!("{foo}", foo = "test",);
+}
+
+// Basic test to make sure that we can invoke the `write!` macro with an
+// fmt::Write instance.
+#[test]
+fn test_write() {
+    let mut buf = String::new();
+    let _ = write!(&mut buf, "{}", 3);
+    {
+        let w = &mut buf;
+        let _ = write!(w, "{foo}", foo = 4);
+        let _ = write!(w, "{}", "hello");
+        let _ = writeln!(w, "{}", "line");
+        let _ = writeln!(w, "{foo}", foo = "bar");
+        let _ = w.write_char('☃');
+        let _ = w.write_str("str");
+    }
+
+    t!(buf, "34helloline\nbar\n☃str");
+}
+
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+#[test]
+fn test_print() {
+    print!("hi");
+    print!("{:?}", vec![0u8]);
+    println!("hello");
+    println!("this is a {}", "test");
+    println!("{foo}", foo = "bar");
+}
+
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+#[test]
+fn test_format_args() {
+    let mut buf = String::new();
+    {
+        let w = &mut buf;
+        let _ = write!(w, "{}", format_args!("{}", 1));
+        let _ = write!(w, "{}", format_args!("test"));
+        let _ = write!(w, "{}", format_args!("{test}", test = 3));
+    }
+    let s = buf;
+    t!(s, "1test3");
+
+    let s = fmt::format(format_args!("hello {}", "world"));
+    t!(s, "hello world");
+    let s = format!("{}: {}", "args were", format_args!("hello {}", "world"));
+    t!(s, "args were: hello world");
+}
+
+#[test]
+fn test_order() {
+    // Make sure format!() arguments are always evaluated in a left-to-right
+    // ordering
+    fn foo() -> isize {
+        static mut FOO: isize = 0;
+        unsafe {
+            FOO += 1;
+            FOO
+        }
+    }
+    assert_eq!(
+        format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()),
+        "1 2 4 5 3 6".to_string()
+    );
+}
+
+#[test]
+fn test_once() {
+    // Make sure each argument are evaluated only once even though it may be
+    // formatted multiple times
+    fn foo() -> isize {
+        static mut FOO: isize = 0;
+        unsafe {
+            FOO += 1;
+            FOO
+        }
+    }
+    assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string());
+}
+
+#[test]
+fn test_refcell() {
+    let refcell = RefCell::new(5);
+    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+    let borrow = refcell.borrow_mut();
+    assert_eq!(format!("{:?}", refcell), "RefCell { value: <borrowed> }");
+    drop(borrow);
+    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
+}
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index cff8ff9..b7cc03f 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -20,6 +20,7 @@
 #![feature(inplace_iteration)]
 #![feature(iter_map_while)]
 #![feature(int_bits_const)]
+#![feature(vecdeque_binary_search)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index a49ca7c..771a293 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1,4 +1,5 @@
 use std::borrow::Cow;
+use std::cell::Cell;
 use std::collections::TryReserveError::*;
 use std::fmt::Debug;
 use std::iter::InPlaceIterable;
@@ -1798,7 +1799,7 @@
 }
 
 macro_rules! assert_partial_eq_valid {
-    ($a2:ident, $a3:ident; $b2:ident, $b3: ident) => {
+    ($a2:expr, $a3:expr; $b2:expr, $b3: expr) => {
         assert!($a2 == $b2);
         assert!($a2 != $b3);
         assert!($a3 != $b2);
@@ -1830,4 +1831,84 @@
     assert_partial_eq_valid!(slicemut2,slicemut3; vec2,vec3);
     assert_partial_eq_valid!(vec2,vec3; array2,array3);
     assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3);
+    assert_partial_eq_valid!(vec2,vec3; arrayref2[..],arrayref3[..]);
+}
+
+#[test]
+fn test_vec_cycle() {
+    #[derive(Debug)]
+    struct C<'a> {
+        v: Vec<Cell<Option<&'a C<'a>>>>,
+    }
+
+    impl<'a> C<'a> {
+        fn new() -> C<'a> {
+            C { v: Vec::new() }
+        }
+    }
+
+    let mut c1 = C::new();
+    let mut c2 = C::new();
+    let mut c3 = C::new();
+
+    // Push
+    c1.v.push(Cell::new(None));
+    c1.v.push(Cell::new(None));
+
+    c2.v.push(Cell::new(None));
+    c2.v.push(Cell::new(None));
+
+    c3.v.push(Cell::new(None));
+    c3.v.push(Cell::new(None));
+
+    // Set
+    c1.v[0].set(Some(&c2));
+    c1.v[1].set(Some(&c3));
+
+    c2.v[0].set(Some(&c2));
+    c2.v[1].set(Some(&c3));
+
+    c3.v[0].set(Some(&c1));
+    c3.v[1].set(Some(&c2));
+}
+
+#[test]
+fn test_vec_cycle_wrapped() {
+    struct Refs<'a> {
+        v: Vec<Cell<Option<&'a C<'a>>>>,
+    }
+
+    struct C<'a> {
+        refs: Refs<'a>,
+    }
+
+    impl<'a> Refs<'a> {
+        fn new() -> Refs<'a> {
+            Refs { v: Vec::new() }
+        }
+    }
+
+    impl<'a> C<'a> {
+        fn new() -> C<'a> {
+            C { refs: Refs::new() }
+        }
+    }
+
+    let mut c1 = C::new();
+    let mut c2 = C::new();
+    let mut c3 = C::new();
+
+    c1.refs.v.push(Cell::new(None));
+    c1.refs.v.push(Cell::new(None));
+    c2.refs.v.push(Cell::new(None));
+    c2.refs.v.push(Cell::new(None));
+    c3.refs.v.push(Cell::new(None));
+    c3.refs.v.push(Cell::new(None));
+
+    c1.refs.v[0].set(Some(&c2));
+    c1.refs.v[1].set(Some(&c3));
+    c2.refs.v[0].set(Some(&c2));
+    c2.refs.v[1].set(Some(&c3));
+    c3.refs.v[0].set(Some(&c1));
+    c3.refs.v[1].set(Some(&c2));
 }
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index 46d8a3c..05cb3a2 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -1659,3 +1659,42 @@
     drop(v);
     assert_eq!(unsafe { DROPS }, 7);
 }
+
+#[test]
+fn test_binary_search() {
+    // Contiguous (front only) search:
+    let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into();
+    assert!(deque.as_slices().1.is_empty());
+    assert_eq!(deque.binary_search(&3), Ok(2));
+    assert_eq!(deque.binary_search(&4), Err(3));
+
+    // Split search (both front & back non-empty):
+    let mut deque: VecDeque<_> = vec![5, 6].into();
+    deque.push_front(3);
+    deque.push_front(2);
+    deque.push_front(1);
+    deque.push_back(10);
+    assert!(!deque.as_slices().0.is_empty());
+    assert!(!deque.as_slices().1.is_empty());
+    assert_eq!(deque.binary_search(&0), Err(0));
+    assert_eq!(deque.binary_search(&1), Ok(0));
+    assert_eq!(deque.binary_search(&5), Ok(3));
+    assert_eq!(deque.binary_search(&7), Err(5));
+    assert_eq!(deque.binary_search(&20), Err(6));
+}
+
+#[test]
+fn test_binary_search_by() {
+    let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into();
+
+    assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&3)), Ok(2));
+    assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&4)), Err(3));
+}
+
+#[test]
+fn test_binary_search_by_key() {
+    let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into();
+
+    assert_eq!(deque.binary_search_by_key(&3, |&(v,)| v), Ok(2));
+    assert_eq!(deque.binary_search_by_key(&4, |&(v,)| v), Err(3));
+}
diff --git a/library/backtrace b/library/backtrace
index 4083a90..a6dd47b 160000
--- a/library/backtrace
+++ b/library/backtrace
@@ -1 +1 @@
-Subproject commit 4083a90168d605b682ba166a0c01f86b3384e474
+Subproject commit a6dd47bd588c882e735675a1379d2b61719fa380
diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs
index 05dd7ad..bc59c37 100644
--- a/library/core/benches/ascii.rs
+++ b/library/core/benches/ascii.rs
@@ -253,9 +253,9 @@
     };
 }
 
-const SHORT: &'static str = "Alice's";
-const MEDIUM: &'static str = "Alice's Adventures in Wonderland";
-const LONG: &'static str = repeat!(
+const SHORT: &str = "Alice's";
+const MEDIUM: &str = "Alice's Adventures in Wonderland";
+const LONG: &str = repeat!(
     r#"
     La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850)
     Alice's Adventures in Wonderland (1865)
diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs
index dd72a33..2792181 100644
--- a/library/core/benches/fmt.rs
+++ b/library/core/benches/fmt.rs
@@ -108,3 +108,32 @@
         }
     });
 }
+
+#[bench]
+fn write_u128_max(bh: &mut Bencher) {
+    bh.iter(|| {
+        std::hint::black_box(format!("{}", u128::MAX));
+    });
+}
+
+#[bench]
+fn write_u128_min(bh: &mut Bencher) {
+    bh.iter(|| {
+        let s = format!("{}", 0u128);
+        std::hint::black_box(s);
+    });
+}
+
+#[bench]
+fn write_u64_max(bh: &mut Bencher) {
+    bh.iter(|| {
+        std::hint::black_box(format!("{}", u64::MAX));
+    });
+}
+
+#[bench]
+fn write_u64_min(bh: &mut Bencher) {
+    bh.iter(|| {
+        std::hint::black_box(format!("{}", 0u64));
+    });
+}
diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs
index f9eb898..c61c19c 100644
--- a/library/core/src/alloc/mod.rs
+++ b/library/core/src/alloc/mod.rs
@@ -13,17 +13,17 @@
 use crate::fmt;
 use crate::ptr::{self, NonNull};
 
-/// The `AllocErr` error indicates an allocation failure
+/// The `AllocError` error indicates an allocation failure
 /// that may be due to resource exhaustion or to
 /// something wrong when combining the given input arguments with this
 /// allocator.
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct AllocErr;
+pub struct AllocError;
 
 // (we need this for downstream impl of trait Error)
 #[unstable(feature = "allocator_api", issue = "32838")]
-impl fmt::Display for AllocErr {
+impl fmt::Display for AllocError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str("memory allocation failed")
     }
@@ -89,13 +89,11 @@
 pub unsafe trait AllocRef {
     /// Attempts to allocate a block of memory.
     ///
-    /// On success, returns a [`NonNull<[u8]>`] meeting the size and alignment guarantees of `layout`.
+    /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`.
     ///
     /// The returned block may have a larger size than specified by `layout.size()`, and may or may
     /// not have its contents initialized.
     ///
-    /// [`NonNull<[u8]>`]: NonNull
-    ///
     /// # Errors
     ///
     /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
@@ -109,7 +107,7 @@
     /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
     ///
     /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
-    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr>;
+    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
 
     /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized.
     ///
@@ -126,7 +124,7 @@
     /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
     ///
     /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
-    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         let ptr = self.alloc(layout)?;
         // SAFETY: `alloc` returns a valid memory block
         unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) }
@@ -146,7 +144,7 @@
 
     /// Attempts to extend the memory block.
     ///
-    /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated
+    /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
     /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
     /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout.
     ///
@@ -158,8 +156,6 @@
     /// If this method returns `Err`, then ownership of the memory block has not been transferred to
     /// this allocator, and the contents of the memory block are unaltered.
     ///
-    /// [`NonNull<[u8]>`]: NonNull
-    ///
     /// # Safety
     ///
     /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
@@ -187,7 +183,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() >= old_layout.size(),
             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
@@ -248,7 +244,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() >= old_layout.size(),
             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
@@ -271,7 +267,7 @@
 
     /// Attempts to shrink the memory block.
     ///
-    /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated
+    /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
     /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
     /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
     ///
@@ -283,8 +279,6 @@
     /// If this method returns `Err`, then ownership of the memory block has not been transferred to
     /// this allocator, and the contents of the memory block are unaltered.
     ///
-    /// [`NonNull<[u8]>`]: NonNull
-    ///
     /// # Safety
     ///
     /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
@@ -312,7 +306,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() <= old_layout.size(),
             "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
@@ -337,7 +331,7 @@
     ///
     /// The returned adaptor also implements `AllocRef` and will simply borrow this.
     #[inline(always)]
-    fn by_ref(&mut self) -> &Self {
+    fn by_ref(&self) -> &Self {
         self
     }
 }
@@ -348,12 +342,12 @@
     A: AllocRef + ?Sized,
 {
     #[inline]
-    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         (**self).alloc(layout)
     }
 
     #[inline]
-    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         (**self).alloc_zeroed(layout)
     }
 
@@ -369,7 +363,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: the safety contract must be upheld by the caller
         unsafe { (**self).grow(ptr, old_layout, new_layout) }
     }
@@ -380,7 +374,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: the safety contract must be upheld by the caller
         unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
     }
@@ -391,7 +385,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: the safety contract must be upheld by the caller
         unsafe { (**self).shrink(ptr, old_layout, new_layout) }
     }
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 15ec13c..7140218 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -226,7 +226,7 @@
 /// assert_eq!(my_struct.special_field.get(), new_value);
 /// ```
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(transparent)]
 pub struct Cell<T: ?Sized> {
@@ -566,7 +566,7 @@
 
 /// A mutable memory location with dynamically checked borrow rules
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RefCell<T: ?Sized> {
     borrow: Cell<BorrowFlag>,
@@ -1203,7 +1203,7 @@
 /// Wraps a borrowed reference to a value in a `RefCell` box.
 /// A wrapper type for an immutably borrowed value from a `RefCell<T>`.
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Ref<'b, T: ?Sized + 'b> {
     value: &'b T,
@@ -1493,7 +1493,7 @@
 
 /// A wrapper type for a mutably borrowed value from a `RefCell<T>`.
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RefMut<'b, T: ?Sized + 'b> {
     value: &'b mut T,
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 2603ecf..1b847ad 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -1229,10 +1229,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_alphabetic(&self) -> bool {
-        match *self {
-            'A'..='Z' | 'a'..='z' => true,
-            _ => false,
-        }
+        matches!(*self, 'A'..='Z' | 'a'..='z')
     }
 
     /// Checks if the value is an ASCII uppercase character:
@@ -1265,10 +1262,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_uppercase(&self) -> bool {
-        match *self {
-            'A'..='Z' => true,
-            _ => false,
-        }
+        matches!(*self, 'A'..='Z')
     }
 
     /// Checks if the value is an ASCII lowercase character:
@@ -1301,10 +1295,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_lowercase(&self) -> bool {
-        match *self {
-            'a'..='z' => true,
-            _ => false,
-        }
+        matches!(*self, 'a'..='z')
     }
 
     /// Checks if the value is an ASCII alphanumeric character:
@@ -1340,10 +1331,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_alphanumeric(&self) -> bool {
-        match *self {
-            '0'..='9' | 'A'..='Z' | 'a'..='z' => true,
-            _ => false,
-        }
+        matches!(*self, '0'..='9' | 'A'..='Z' | 'a'..='z')
     }
 
     /// Checks if the value is an ASCII decimal digit:
@@ -1376,10 +1364,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_digit(&self) -> bool {
-        match *self {
-            '0'..='9' => true,
-            _ => false,
-        }
+        matches!(*self, '0'..='9')
     }
 
     /// Checks if the value is an ASCII hexadecimal digit:
@@ -1415,10 +1400,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_hexdigit(&self) -> bool {
-        match *self {
-            '0'..='9' | 'A'..='F' | 'a'..='f' => true,
-            _ => false,
-        }
+        matches!(*self, '0'..='9' | 'A'..='F' | 'a'..='f')
     }
 
     /// Checks if the value is an ASCII punctuation character:
@@ -1455,10 +1437,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_punctuation(&self) -> bool {
-        match *self {
-            '!'..='/' | ':'..='@' | '['..='`' | '{'..='~' => true,
-            _ => false,
-        }
+        matches!(*self, '!'..='/' | ':'..='@' | '['..='`' | '{'..='~')
     }
 
     /// Checks if the value is an ASCII graphic character:
@@ -1491,10 +1470,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_graphic(&self) -> bool {
-        match *self {
-            '!'..='~' => true,
-            _ => false,
-        }
+        matches!(*self, '!'..='~')
     }
 
     /// Checks if the value is an ASCII whitespace character:
@@ -1544,10 +1520,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_whitespace(&self) -> bool {
-        match *self {
-            '\t' | '\n' | '\x0C' | '\r' | ' ' => true,
-            _ => false,
-        }
+        matches!(*self, '\t' | '\n' | '\x0C' | '\r' | ' ')
     }
 
     /// Checks if the value is an ASCII control character:
@@ -1582,10 +1555,7 @@
     #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")]
     #[inline]
     pub const fn is_ascii_control(&self) -> bool {
-        match *self {
-            '\0'..='\x1F' | '\x7F' => true,
-            _ => false,
-        }
+        matches!(*self, '\0'..='\x1F' | '\x7F')
     }
 }
 
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 2bfeb49..3f7110b 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -134,6 +134,7 @@
 /// want to accept all references that can be converted to [`&str`] as an argument.
 /// Since both [`String`] and [`&str`] implement `AsRef<str>` we can accept both as input argument.
 ///
+/// [`&str`]: primitive@str
 /// [`Option<T>`]: Option
 /// [`Result<T, E>`]: Result
 /// [`Borrow`]: crate::borrow::Borrow
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs
index 336c0b2..2dd5e81 100644
--- a/library/core/src/convert/num.rs
+++ b/library/core/src/convert/num.rs
@@ -485,3 +485,49 @@
 nzint_impl_try_from_int! { i64, NonZeroI64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
 nzint_impl_try_from_int! { i128, NonZeroI128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
 nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] }
+
+macro_rules! nzint_impl_try_from_nzint {
+    ($From:ty => $To:ty, $doc: expr) => {
+        #[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")]
+        #[doc = $doc]
+        impl TryFrom<$From> for $To {
+            type Error = TryFromIntError;
+
+            #[inline]
+            fn try_from(value: $From) -> Result<Self, Self::Error> {
+                TryFrom::try_from(value.get()).map(|v| {
+                    // SAFETY: $From is a NonZero type, so v is not zero.
+                    unsafe { Self::new_unchecked(v) }
+                })
+            }
+        }
+    };
+    ($To:ty: $($From: ty),*) => {$(
+        nzint_impl_try_from_nzint!(
+            $From => $To,
+            concat!(
+                "Attempts to convert `",
+                stringify!($From),
+                "` to `",
+                stringify!($To),
+                "`.",
+            )
+        );
+    )*};
+}
+
+// Non-zero int -> non-zero unsigned int
+nzint_impl_try_from_nzint! { NonZeroU8: NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroU16: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroU32: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroU64: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroU128: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroUsize: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroIsize }
+
+// Non-zero int -> non-zero signed int
+nzint_impl_try_from_nzint! { NonZeroI8: NonZeroU8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroI16: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroI32: NonZeroU32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroI64: NonZeroU64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroI128: NonZeroU128, NonZeroUsize, NonZeroIsize }
+nzint_impl_try_from_nzint! { NonZeroIsize: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize }
diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs
index 4525ba7..e146a97 100644
--- a/library/core/src/ffi.rs
+++ b/library/core/src/ffi.rs
@@ -280,7 +280,7 @@
 // within a private module. Once RFC 2145 has been implemented look into
 // improving this.
 mod sealed_trait {
-    /// Trait which permits the allowed types to be used with [VaList::arg].
+    /// Trait which permits the allowed types to be used with [super::VaListImpl::arg].
     #[unstable(
         feature = "c_variadic",
         reason = "the `c_variadic` feature has not been properly tested on \
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 8558cb5..0963c6d 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -92,18 +92,14 @@
 #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub struct Error;
 
-/// A collection of methods that are required to format a message into a stream.
+/// A trait for writing or formatting into Unicode-accepting buffers or streams.
 ///
-/// This trait is the type which this modules requires when formatting
-/// information. This is similar to the standard library's [`io::Write`] trait,
-/// but it is only intended for use in libcore.
+/// This trait only accepts UTF-8–encoded data and is not [flushable]. If you only
+/// want to accept Unicode and you don't need flushing, you should implement this trait;
+/// otherwise you should implement [`std::io::Write`].
 ///
-/// This trait should generally not be implemented by consumers of the standard
-/// library. The [`write!`] macro accepts an instance of [`io::Write`], and the
-/// [`io::Write`] trait is favored over implementing this trait.
-///
-/// [`write!`]: ../../std/macro.write.html
-/// [`io::Write`]: ../../std/io/trait.Write.html
+/// [`std::io::Write`]: ../../std/io/trait.Write.html
+/// [flushable]: ../../std/io/trait.Write.html#tymethod.flush
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Write {
     /// Writes a string slice into this writer, returning whether the write
@@ -1058,7 +1054,7 @@
 /// assert_eq!(output, "Hello world!");
 /// ```
 ///
-/// [`write!`]: ../../std/macro.write.html
+/// [`write!`]: crate::write!
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
     let mut formatter = Formatter {
@@ -1886,7 +1882,7 @@
     /// assert_eq!(format!("{:?}", Foo(vec![10, 11])), "{10, 11}");
     /// ```
     ///
-    /// [`format_args!`]: ../../std/macro.format_args.html
+    /// [`format_args!`]: crate::format_args
     ///
     /// In this more complex example, we use [`format_args!`] and `.debug_set()`
     /// to build a list of match arms:
@@ -2238,5 +2234,6 @@
     }
 }
 
-// If you expected tests to be here, look instead at the ui/ifmt.rs test,
+// If you expected tests to be here, look instead at the core/tests/fmt.rs file,
 // it's a lot easier than creating all of the rt::Piece structures here.
+// There are also tests in the alloc crate, for those that need allocations.
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index ae3d0dd..795cbf5 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -9,7 +9,7 @@
 use crate::str;
 
 #[doc(hidden)]
-trait Int:
+trait DisplayInt:
     PartialEq + PartialOrd + Div<Output = Self> + Rem<Output = Self> + Sub<Output = Self> + Copy
 {
     fn zero() -> Self;
@@ -21,22 +21,39 @@
     fn to_u128(&self) -> u128;
 }
 
-macro_rules! doit {
-    ($($t:ident)*) => ($(impl Int for $t {
-        fn zero() -> Self { 0 }
-        fn from_u8(u: u8) -> Self { u as Self }
-        fn to_u8(&self) -> u8 { *self as u8 }
-        fn to_u16(&self) -> u16 { *self as u16 }
-        fn to_u32(&self) -> u32 { *self as u32 }
-        fn to_u64(&self) -> u64 { *self as u64 }
-        fn to_u128(&self) -> u128 { *self as u128 }
-    })*)
+macro_rules! impl_int {
+    ($($t:ident)*) => (
+      $(impl DisplayInt for $t {
+          fn zero() -> Self { 0 }
+          fn from_u8(u: u8) -> Self { u as Self }
+          fn to_u8(&self) -> u8 { *self as u8 }
+          fn to_u16(&self) -> u16 { *self as u16 }
+          fn to_u32(&self) -> u32 { *self as u32 }
+          fn to_u64(&self) -> u64 { *self as u64 }
+          fn to_u128(&self) -> u128 { *self as u128 }
+      })*
+    )
 }
-doit! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
+macro_rules! impl_uint {
+    ($($t:ident)*) => (
+      $(impl DisplayInt for $t {
+          fn zero() -> Self { 0 }
+          fn from_u8(u: u8) -> Self { u as Self }
+          fn to_u8(&self) -> u8 { *self as u8 }
+          fn to_u16(&self) -> u16 { *self as u16 }
+          fn to_u32(&self) -> u32 { *self as u32 }
+          fn to_u64(&self) -> u64 { *self as u64 }
+          fn to_u128(&self) -> u128 { *self as u128 }
+      })*
+    )
+}
+
+impl_int! { i8 i16 i32 i64 i128 isize }
+impl_uint! { u8 u16 u32 u64 u128 usize }
 
 /// A type that represents a specific radix
 #[doc(hidden)]
-trait GenericRadix {
+trait GenericRadix: Sized {
     /// The number of digits.
     const BASE: u8;
 
@@ -47,7 +64,7 @@
     fn digit(x: u8) -> u8;
 
     /// Format an integer using the radix using a formatter.
-    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    fn fmt_int<T: DisplayInt>(&self, mut x: T, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // The radix can be as low as 2, so we need a buffer of at least 128
         // characters for a base 2 number.
         let zero = T::zero();
@@ -127,13 +144,11 @@
 
 radix! { Binary,    2, "0b", x @  0 ..=  1 => b'0' + x }
 radix! { Octal,     8, "0o", x @  0 ..=  7 => b'0' + x }
-radix! { LowerHex, 16, "0x", x @  0 ..=  9 => b'0' + x,
-x @ 10 ..= 15 => b'a' + (x - 10) }
-radix! { UpperHex, 16, "0x", x @  0 ..=  9 => b'0' + x,
-x @ 10 ..= 15 => b'A' + (x - 10) }
+radix! { LowerHex, 16, "0x", x @  0 ..=  9 => b'0' + x, x @ 10 ..= 15 => b'a' + (x - 10) }
+radix! { UpperHex, 16, "0x", x @  0 ..=  9 => b'0' + x, x @ 10 ..= 15 => b'A' + (x - 10) }
 
 macro_rules! int_base {
-    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
+    (fmt::$Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
         impl fmt::$Trait for $T {
             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -143,8 +158,27 @@
     };
 }
 
+macro_rules! integer {
+    ($Int:ident, $Uint:ident) => {
+        int_base! { fmt::Binary   for $Int as $Uint  -> Binary }
+        int_base! { fmt::Octal    for $Int as $Uint  -> Octal }
+        int_base! { fmt::LowerHex for $Int as $Uint  -> LowerHex }
+        int_base! { fmt::UpperHex for $Int as $Uint  -> UpperHex }
+
+        int_base! { fmt::Binary   for $Uint as $Uint -> Binary }
+        int_base! { fmt::Octal    for $Uint as $Uint -> Octal }
+        int_base! { fmt::LowerHex for $Uint as $Uint -> LowerHex }
+        int_base! { fmt::UpperHex for $Uint as $Uint -> UpperHex }
+    };
+}
+integer! { isize, usize }
+integer! { i8, u8 }
+integer! { i16, u16 }
+integer! { i32, u32 }
+integer! { i64, u64 }
+integer! { i128, u128 }
 macro_rules! debug {
-    ($T:ident) => {
+    ($($T:ident)*) => {$(
         #[stable(feature = "rust1", since = "1.0.0")]
         impl fmt::Debug for $T {
             #[inline]
@@ -158,31 +192,14 @@
                 }
             }
         }
-    };
+    )*};
+}
+debug! {
+  i8 i16 i32 i64 i128 isize
+  u8 u16 u32 u64 u128 usize
 }
 
-macro_rules! integer {
-    ($Int:ident, $Uint:ident) => {
-        int_base! { Binary   for $Int as $Uint  -> Binary }
-        int_base! { Octal    for $Int as $Uint  -> Octal }
-        int_base! { LowerHex for $Int as $Uint  -> LowerHex }
-        int_base! { UpperHex for $Int as $Uint  -> UpperHex }
-        debug! { $Int }
-
-        int_base! { Binary   for $Uint as $Uint -> Binary }
-        int_base! { Octal    for $Uint as $Uint -> Octal }
-        int_base! { LowerHex for $Uint as $Uint -> LowerHex }
-        int_base! { UpperHex for $Uint as $Uint -> UpperHex }
-        debug! { $Uint }
-    };
-}
-integer! { isize, usize }
-integer! { i8, u8 }
-integer! { i16, u16 }
-integer! { i32, u32 }
-integer! { i64, u64 }
-integer! { i128, u128 }
-
+// 2 digit decimal look up table
 static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
       2021222324252627282930313233343536373839\
       4041424344454647484950515253545556575859\
@@ -256,21 +273,20 @@
             f.pad_integral(is_nonnegative, "", buf_slice)
         }
 
-        $(
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl fmt::Display for $t {
-                #[allow(unused_comparisons)]
-                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                    let is_nonnegative = *self >= 0;
-                    let n = if is_nonnegative {
-                        self.$conv_fn()
-                    } else {
-                        // convert the negative num to positive by summing 1 to it's 2 complement
-                        (!self.$conv_fn()).wrapping_add(1)
-                    };
-                    $name(n, is_nonnegative, f)
-                }
-            })*
+        $(#[stable(feature = "rust1", since = "1.0.0")]
+        impl fmt::Display for $t {
+            #[allow(unused_comparisons)]
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                let is_nonnegative = *self >= 0;
+                let n = if is_nonnegative {
+                    self.$conv_fn()
+                } else {
+                    // convert the negative num to positive by summing 1 to it's 2 complement
+                    (!self.$conv_fn()).wrapping_add(1)
+                };
+                $name(n, is_nonnegative, f)
+            }
+        })*
     };
 }
 
@@ -461,6 +477,185 @@
     impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
     impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
 }
-
-impl_Display!(i128, u128 as u128 via to_u128 named fmt_u128);
 impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
+
+/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
+fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut isize) {
+    let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf);
+    let lut_ptr = DEC_DIGITS_LUT.as_ptr();
+    assert!(*curr > 19);
+
+    // SAFETY:
+    // Writes at most 19 characters into the buffer. Guaranteed that any ptr into LUT is at most
+    // 198, so will never OOB. There is a check above that there are at least 19 characters
+    // remaining.
+    unsafe {
+        if n >= 1e16 as u64 {
+            let to_parse = n % 1e16 as u64;
+            n /= 1e16 as u64;
+
+            // Some of these are nops but it looks more elegant this way.
+            let d1 = ((to_parse / 1e14 as u64) % 100) << 1;
+            let d2 = ((to_parse / 1e12 as u64) % 100) << 1;
+            let d3 = ((to_parse / 1e10 as u64) % 100) << 1;
+            let d4 = ((to_parse / 1e8 as u64) % 100) << 1;
+            let d5 = ((to_parse / 1e6 as u64) % 100) << 1;
+            let d6 = ((to_parse / 1e4 as u64) % 100) << 1;
+            let d7 = ((to_parse / 1e2 as u64) % 100) << 1;
+            let d8 = ((to_parse / 1e0 as u64) % 100) << 1;
+
+            *curr -= 16;
+
+            ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d3 as isize), buf_ptr.offset(*curr + 4), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d4 as isize), buf_ptr.offset(*curr + 6), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d5 as isize), buf_ptr.offset(*curr + 8), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d6 as isize), buf_ptr.offset(*curr + 10), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d7 as isize), buf_ptr.offset(*curr + 12), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d8 as isize), buf_ptr.offset(*curr + 14), 2);
+        }
+        if n >= 1e8 as u64 {
+            let to_parse = n % 1e8 as u64;
+            n /= 1e8 as u64;
+
+            // Some of these are nops but it looks more elegant this way.
+            let d1 = ((to_parse / 1e6 as u64) % 100) << 1;
+            let d2 = ((to_parse / 1e4 as u64) % 100) << 1;
+            let d3 = ((to_parse / 1e2 as u64) % 100) << 1;
+            let d4 = ((to_parse / 1e0 as u64) % 100) << 1;
+            *curr -= 8;
+
+            ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d3 as isize), buf_ptr.offset(*curr + 4), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d4 as isize), buf_ptr.offset(*curr + 6), 2);
+        }
+        // `n` < 1e8 < (1 << 32)
+        let mut n = n as u32;
+        if n >= 1e4 as u32 {
+            let to_parse = n % 1e4 as u32;
+            n /= 1e4 as u32;
+
+            let d1 = (to_parse / 100) << 1;
+            let d2 = (to_parse % 100) << 1;
+            *curr -= 4;
+
+            ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2);
+            ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2);
+        }
+
+        // `n` < 1e4 < (1 << 16)
+        let mut n = n as u16;
+        if n >= 100 {
+            let d1 = (n % 100) << 1;
+            n /= 100;
+            *curr -= 2;
+            ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr), 2);
+        }
+
+        // decode last 1 or 2 chars
+        if n < 10 {
+            *curr -= 1;
+            *buf_ptr.offset(*curr) = (n as u8) + b'0';
+        } else {
+            let d1 = n << 1;
+            *curr -= 2;
+            ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr), 2);
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for u128 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt_u128(*self, true, f)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for i128 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let is_nonnegative = *self >= 0;
+        let n = if is_nonnegative {
+            self.to_u128()
+        } else {
+            // convert the negative num to positive by summing 1 to it's 2 complement
+            (!self.to_u128()).wrapping_add(1)
+        };
+        fmt_u128(n, is_nonnegative, f)
+    }
+}
+
+/// Specialized optimization for u128. Instead of taking two items at a time, it splits
+/// into at most 2 u64s, and then chunks by 10e16, 10e8, 10e4, 10e2, and then 10e1.
+/// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas
+/// 10^20 > 2^64 > 10^19.
+fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    // 2^128 is about 3*10^38, so 39 gives an extra byte of space
+    let mut buf = [MaybeUninit::<u8>::uninit(); 39];
+    let mut curr = buf.len() as isize;
+    let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
+
+    let (n, rem) = udiv_1e19(n);
+    parse_u64_into(rem, &mut buf, &mut curr);
+
+    if n != 0 {
+        // 0 pad up to point
+        let target = (buf.len() - 19) as isize;
+        // SAFETY: Guaranteed that we wrote at most 19 bytes, and there must be space
+        // remaining since it has length 39
+        unsafe {
+            ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
+        }
+        curr = target;
+
+        let (n, rem) = udiv_1e19(n);
+        parse_u64_into(rem, &mut buf, &mut curr);
+        // Should this following branch be annotated with unlikely?
+        if n != 0 {
+            let target = (buf.len() - 38) as isize;
+            // SAFETY: At this point we wrote at most 38 bytes, pad up to that point,
+            // There can only be at most 1 digit remaining.
+            unsafe {
+                ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
+                curr = target - 1;
+                *buf_ptr.offset(curr) = (n as u8) + b'0';
+            }
+        }
+    }
+
+    // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
+    // UTF-8 since `DEC_DIGITS_LUT` is
+    let buf_slice = unsafe {
+        str::from_utf8_unchecked(slice::from_raw_parts(
+            buf_ptr.offset(curr),
+            buf.len() - curr as usize,
+        ))
+    };
+    f.pad_integral(is_nonnegative, "", buf_slice)
+}
+
+/// Partition of `n` into n > 1e19 and rem <= 1e19
+fn udiv_1e19(n: u128) -> (u128, u64) {
+    const DIV: u64 = 1e19 as u64;
+    let high = (n >> 64) as u64;
+    if high == 0 {
+        let low = n as u64;
+        return ((low / DIV) as u128, low % DIV);
+    }
+    let sr = 65 - high.leading_zeros();
+    let mut q = n << (128 - sr);
+    let mut r = n >> sr;
+    let mut carry = 0;
+
+    for _ in 0..sr {
+        r = (r << 1) | (q >> 127);
+        q = (q << 1) | carry as u128;
+
+        let s = (DIV as u128).wrapping_sub(r).wrapping_sub(1) as i128 >> 127;
+        carry = (s & 1) as u64;
+        r -= (DIV as u128) & s as u128;
+    }
+    ((q << 1) | carry as u128, r as u64)
+}
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 4eb47dd..454fb34 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -98,8 +98,6 @@
 /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
 /// `black_box` could do.
 ///
-/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html
-///
 /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
 /// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
 /// behavior in the calling code. This property makes `black_box` useful for writing code in which
@@ -108,6 +106,8 @@
 /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
 /// extent to which it can block optimisations may vary depending upon the platform and code-gen
 /// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
+///
+/// [`std::convert::identity`]: crate::convert::identity
 #[cfg_attr(not(miri), inline)]
 #[cfg_attr(miri, inline(never))]
 #[unstable(feature = "test", issue = "50297")]
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 243fc7b..dbc7921 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1072,7 +1072,7 @@
     // NOTE: While this makes the intrinsic const stable, we have some custom code in const fn
     // checks that prevent its use within `const fn`.
     #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")]
-    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "transmute")]
+    #[rustc_diagnostic_item = "transmute"]
     pub fn transmute<T, U>(e: T) -> U;
 
     /// Returns `true` if the actual type given as `T` requires drop
@@ -1082,7 +1082,7 @@
     /// If the actual type neither requires drop glue nor implements
     /// `Copy`, then the return value of this function is unspecified.
     ///
-    /// The stabilized version of this intrinsic is [`needs_drop`].
+    /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
     #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
     pub fn needs_drop<T>() -> bool;
 
@@ -1660,22 +1660,22 @@
     /// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
     ///
     /// The stabilized versions of this intrinsic are available on the integer
-    /// primitives via the `checked_add` method. For example,
-    /// [`u32::checked_add`]
+    /// primitives via the `wrapping_add` method. For example,
+    /// [`u32::wrapping_add`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
     pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
     /// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
     ///
     /// The stabilized versions of this intrinsic are available on the integer
-    /// primitives via the `checked_sub` method. For example,
-    /// [`u32::checked_sub`]
+    /// primitives via the `wrapping_sub` method. For example,
+    /// [`u32::wrapping_sub`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
     pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
     /// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
     ///
     /// The stabilized versions of this intrinsic are available on the integer
-    /// primitives via the `checked_mul` method. For example,
-    /// [`u32::checked_mul`]
+    /// primitives via the `wrapping_mul` method. For example,
+    /// [`u32::wrapping_mul`]
     #[rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0")]
     pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
 
@@ -1901,11 +1901,22 @@
 /// ```
 /// use std::ptr;
 ///
+/// /// # Safety
+/// ///
+/// /// * `ptr` must be correctly aligned for its type and non-zero.
+/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
+/// /// * Those elements must not be used after calling this function unless `T: Copy`.
 /// # #[allow(dead_code)]
 /// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
 ///     let mut dst = Vec::with_capacity(elts);
-///     dst.set_len(elts);
+///
+///     // SAFETY: Our precondition ensures the source is aligned and valid,
+///     // and `Vec::with_capacity` ensures that we have usable space to write them.
 ///     ptr::copy(ptr, dst.as_mut_ptr(), elts);
+///
+///     // SAFETY: We created it with this much capacity earlier,
+///     // and the previous `copy` has initialized these elements.
+///     dst.set_len(elts);
 ///     dst
 /// }
 /// ```
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index 13c6a75..2e070d7 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -6,6 +6,17 @@
 ///
 /// This `struct` is created by [`Iterator::chain`]. See its documentation
 /// for more.
+///
+/// # Examples
+///
+/// ```
+/// use std::iter::Chain;
+/// use std::slice::Iter;
+///
+/// let a1 = [1, 2, 3];
+/// let a2 = [4, 5, 6];
+/// let iter: Chain<Iter<_>, Iter<_>> = a1.iter().chain(a2.iter());
+/// ```
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -98,7 +109,7 @@
             acc = b.try_fold(acc, f)?;
             // we don't fuse the second iterator
         }
-        Try::from_ok(acc)
+        try { acc }
     }
 
     fn fold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
@@ -115,16 +126,42 @@
     }
 
     #[inline]
-    fn nth(&mut self, mut n: usize) -> Option<A::Item> {
+    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+        let mut rem = n;
+
         if let Some(ref mut a) = self.a {
-            while let Some(x) = a.next() {
-                if n == 0 {
-                    return Some(x);
-                }
-                n -= 1;
+            match a.advance_by(rem) {
+                Ok(()) => return Ok(()),
+                Err(k) => rem -= k,
             }
             self.a = None;
         }
+
+        if let Some(ref mut b) = self.b {
+            match b.advance_by(rem) {
+                Ok(()) => return Ok(()),
+                Err(k) => rem -= k,
+            }
+            // we don't fuse the second iterator
+        }
+
+        if rem == 0 { Ok(()) } else { Err(n - rem) }
+    }
+
+    #[inline]
+    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
+        if let Some(ref mut a) = self.a {
+            match a.advance_by(n) {
+                Ok(()) => match a.next() {
+                    None => n = 0,
+                    x => return x,
+                },
+                Err(k) => n -= k,
+            }
+
+            self.a = None;
+        }
+
         maybe!(self.b.nth(n))
     }
 
@@ -191,16 +228,42 @@
     }
 
     #[inline]
-    fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+        let mut rem = n;
+
         if let Some(ref mut b) = self.b {
-            while let Some(x) = b.next_back() {
-                if n == 0 {
-                    return Some(x);
-                }
-                n -= 1;
+            match b.advance_back_by(rem) {
+                Ok(()) => return Ok(()),
+                Err(k) => rem -= k,
             }
             self.b = None;
         }
+
+        if let Some(ref mut a) = self.a {
+            match a.advance_back_by(rem) {
+                Ok(()) => return Ok(()),
+                Err(k) => rem -= k,
+            }
+            // we don't fuse the second iterator
+        }
+
+        if rem == 0 { Ok(()) } else { Err(n - rem) }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
+        if let Some(ref mut b) = self.b {
+            match b.advance_back_by(n) {
+                Ok(()) => match b.next_back() {
+                    None => n = 0,
+                    x => return x,
+                },
+                Err(k) => n -= k,
+            }
+
+            self.b = None;
+        }
+
         maybe!(self.a.nth_back(n))
     }
 
@@ -229,7 +292,7 @@
             acc = a.try_rfold(acc, f)?;
             // we don't fuse the second iterator
         }
-        Try::from_ok(acc)
+        try { acc }
     }
 
     fn rfold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index ddb1aae..35adb4f 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -317,7 +317,7 @@
         }
         self.backiter = None;
 
-        Try::from_ok(init)
+        try { init }
     }
 
     #[inline]
@@ -397,7 +397,7 @@
         }
         self.frontiter = None;
 
-        Try::from_ok(init)
+        try { init }
     }
 
     #[inline]
diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs
index a78da36..60ac352 100644
--- a/library/core/src/iter/adapters/fuse.rs
+++ b/library/core/src/iter/adapters/fuse.rs
@@ -303,7 +303,7 @@
             acc = iter.try_fold(acc, fold)?;
             self.iter = None;
         }
-        Try::from_ok(acc)
+        try { acc }
     }
 
     #[inline]
@@ -353,7 +353,7 @@
             acc = iter.try_rfold(acc, fold)?;
             self.iter = None;
         }
-        Try::from_ok(acc)
+        try { acc }
     }
 
     #[inline]
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 422e449..bf30dcb 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -125,6 +125,11 @@
     }
 
     #[inline]
+    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+        self.iter.advance_back_by(n)
+    }
+
+    #[inline]
     fn nth(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
         self.iter.nth_back(n)
     }
@@ -165,6 +170,11 @@
     }
 
     #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+        self.iter.advance_by(n)
+    }
+
+    #[inline]
     fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
         self.iter.nth(n)
     }
@@ -569,7 +579,7 @@
         })?;
 
         if is_empty {
-            return Try::from_ok(acc);
+            return try { acc };
         }
 
         loop {
@@ -705,7 +715,7 @@
         if self.first_take {
             self.first_take = false;
             match self.iter.next() {
-                None => return Try::from_ok(acc),
+                None => return try { acc },
                 Some(x) => acc = f(acc, x)?,
             }
         }
@@ -782,7 +792,7 @@
         }
 
         match self.next_back() {
-            None => Try::from_ok(init),
+            None => try { init },
             Some(x) => {
                 let acc = f(init, x)?;
                 from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f)
@@ -1065,7 +1075,7 @@
     predicate: &'a mut impl FnMut(&T) -> bool,
     mut fold: impl FnMut(Acc, T) -> R + 'a,
 ) -> impl FnMut(Acc, T) -> R + 'a {
-    move |acc, item| if predicate(&item) { fold(acc, item) } else { R::from_ok(acc) }
+    move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1219,7 +1229,7 @@
 ) -> impl FnMut(Acc, T) -> R + 'a {
     move |acc, item| match f(item) {
         Some(x) => fold(acc, x),
-        None => R::from_ok(acc),
+        None => try { acc },
     }
 }
 
@@ -1650,7 +1660,7 @@
         R: Try<Ok = B>,
     {
         let acc = match self.peeked.take() {
-            Some(None) => return Try::from_ok(init),
+            Some(None) => return try { init },
             Some(Some(v)) => f(init, v)?,
             None => init,
         };
@@ -1693,7 +1703,7 @@
         R: Try<Ok = B>,
     {
         match self.peeked.take() {
-            Some(None) => Try::from_ok(init),
+            Some(None) => try { init },
             Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                 Ok(acc) => f(acc, v),
                 Err(e) => {
@@ -1928,7 +1938,7 @@
         if !self.flag {
             match self.next() {
                 Some(v) => init = fold(init, v)?,
-                None => return Try::from_ok(init),
+                None => return try { init },
             }
         }
         self.iter.try_fold(init, fold)
@@ -2055,13 +2065,13 @@
                     ControlFlow::from_try(fold(acc, x))
                 } else {
                     *flag = true;
-                    ControlFlow::Break(Try::from_ok(acc))
+                    ControlFlow::Break(try { acc })
                 }
             }
         }
 
         if self.flag {
-            Try::from_ok(init)
+            try { init }
         } else {
             let flag = &mut self.flag;
             let p = &mut self.predicate;
@@ -2170,7 +2180,7 @@
         let Self { iter, predicate } = self;
         iter.try_fold(init, |acc, x| match predicate(x) {
             Some(item) => ControlFlow::from_try(fold(acc, item)),
-            None => ControlFlow::Break(Try::from_ok(acc)),
+            None => ControlFlow::Break(try { acc }),
         })
         .into_try()
     }
@@ -2306,7 +2316,7 @@
         if n > 0 {
             // nth(n) skips n+1
             if self.iter.nth(n - 1).is_none() {
-                return Try::from_ok(init);
+                return try { init };
             }
         }
         self.iter.try_fold(init, fold)
@@ -2371,11 +2381,7 @@
         }
 
         let n = self.len();
-        if n == 0 {
-            Try::from_ok(init)
-        } else {
-            self.iter.try_rfold(init, check(n, fold)).into_try()
-        }
+        if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
     }
 
     fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
@@ -2499,7 +2505,7 @@
         }
 
         if self.n == 0 {
-            Try::from_ok(init)
+            try { init }
         } else {
             let n = &mut self.n;
             self.iter.try_fold(init, check(n, fold)).into_try()
@@ -2577,11 +2583,11 @@
         R: Try<Ok = Acc>,
     {
         if self.n == 0 {
-            Try::from_ok(init)
+            try { init }
         } else {
             let len = self.iter.len();
             if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() {
-                Try::from_ok(init)
+                try { init }
             } else {
                 self.iter.try_rfold(init, fold)
             }
@@ -2677,7 +2683,7 @@
             mut fold: impl FnMut(Acc, B) -> R + 'a,
         ) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
             move |acc, x| match f(state, x) {
-                None => ControlFlow::Break(Try::from_ok(acc)),
+                None => ControlFlow::Break(try { acc }),
                 Some(x) => ControlFlow::from_try(fold(acc, x)),
             }
         }
@@ -2941,7 +2947,7 @@
                 Ok(x) => ControlFlow::from_try(f(acc, x)),
                 Err(e) => {
                     *error = Err(e);
-                    ControlFlow::Break(Try::from_ok(acc))
+                    ControlFlow::Break(try { acc })
                 }
             })
             .into_try()
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 9f34aee..cd8ab11 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -713,7 +713,7 @@
         R: Try<Ok = B>,
     {
         if self.is_empty() {
-            return Try::from_ok(init);
+            return try { init };
         }
 
         let mut accum = init;
@@ -731,7 +731,7 @@
             accum = f(accum, self.start.clone())?;
         }
 
-        Try::from_ok(accum)
+        try { accum }
     }
 
     #[inline]
@@ -818,7 +818,7 @@
         R: Try<Ok = B>,
     {
         if self.is_empty() {
-            return Try::from_ok(init);
+            return try { init };
         }
 
         let mut accum = init;
@@ -836,7 +836,7 @@
             accum = f(accum, self.start.clone())?;
         }
 
-        Try::from_ok(accum)
+        try { accum }
     }
 
     #[inline]
diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs
index 97562cf..44da8f4 100644
--- a/library/core/src/iter/sources.rs
+++ b/library/core/src/iter/sources.rs
@@ -501,9 +501,9 @@
 ///
 /// # Examples
 ///
-/// Let’s re-implement the counter iterator from [module-level documentation]:
+/// Let’s re-implement the counter iterator from the [module-level documentation]:
 ///
-/// [module-level documentation]: index.html
+/// [module-level documentation]: super
 ///
 /// ```
 /// let mut count = 0;
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 41a503c..1ae6d15 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -94,7 +94,7 @@
     ///
     /// See the [module-level documentation] for more.
     ///
-    /// [module-level documentation]: index.html
+    /// [module-level documentation]: crate::iter
     ///
     /// # Examples
     ///
@@ -120,7 +120,7 @@
 /// collection of some kind.
 ///
 /// One benefit of implementing `IntoIterator` is that your type will [work
-/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator).
+/// with Rust's `for` loop syntax](crate::iter#for-loops-and-intoiterator).
 ///
 /// See also: [`FromIterator`].
 ///
@@ -212,7 +212,7 @@
     ///
     /// See the [module-level documentation] for more.
     ///
-    /// [module-level documentation]: index.html
+    /// [module-level documentation]: crate::iter
     ///
     /// # Examples
     ///
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index bc03c14..87fe3c2 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -91,6 +91,49 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     fn next_back(&mut self) -> Option<Self::Item>;
 
+    /// Advances the iterator from the back by `n` elements.
+    ///
+    /// `advance_back_by` is the reverse version of [`advance_by`]. This method will
+    /// eagerly skip `n` elements starting from the back by calling [`next_back`] up
+    /// to `n` times until [`None`] is encountered.
+    ///
+    /// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by
+    /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number of
+    /// elements the iterator is advanced by before running out of elements (i.e. the length
+    /// of the iterator). Note that `k` is always less than `n`.
+    ///
+    /// Calling `advance_back_by(0)` does not consume any elements and always returns [`Ok(())`].
+    ///
+    /// [`advance_by`]: Iterator::advance_by
+    /// [`next_back`]: DoubleEndedIterator::next_back
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_advance_by)]
+    ///
+    /// let a = [3, 4, 5, 6];
+    /// let mut iter = a.iter();
+    ///
+    /// assert_eq!(iter.advance_back_by(2), Ok(()));
+    /// assert_eq!(iter.next_back(), Some(&4));
+    /// assert_eq!(iter.advance_back_by(0), Ok(()));
+    /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped
+    /// ```
+    ///
+    /// [`Ok(())`]: Ok
+    /// [`Err(k)`]: Err
+    #[inline]
+    #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+        for i in 0..n {
+            self.next_back().ok_or(i)?;
+        }
+        Ok(())
+    }
+
     /// Returns the `n`th element from the end of the iterator.
     ///
     /// This is essentially the reversed version of [`Iterator::nth()`].
@@ -134,14 +177,9 @@
     /// ```
     #[inline]
     #[stable(feature = "iter_nth_back", since = "1.37.0")]
-    fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
-        for x in self.rev() {
-            if n == 0 {
-                return Some(x);
-            }
-            n -= 1;
-        }
-        None
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        self.advance_back_by(n).ok()?;
+        self.next_back()
     }
 
     /// This is the reverse version of [`Iterator::try_fold()`]: it takes
@@ -186,7 +224,7 @@
         while let Some(x) = self.next_back() {
             accum = f(accum, x)?;
         }
-        Try::from_ok(accum)
+        try { accum }
     }
 
     /// An iterator method that reduces the iterator's elements to a single,
@@ -318,6 +356,9 @@
     fn next_back(&mut self) -> Option<I::Item> {
         (**self).next_back()
     }
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+        (**self).advance_back_by(n)
+    }
     fn nth_back(&mut self, n: usize) -> Option<I::Item> {
         (**self).nth_back(n)
     }
diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs
index 33ace60..eadbdf4 100644
--- a/library/core/src/iter/traits/exact_size.rs
+++ b/library/core/src/iter/traits/exact_size.rs
@@ -26,10 +26,10 @@
 /// assert_eq!(5, five.len());
 /// ```
 ///
-/// In the [module level docs][moddocs], we implemented an [`Iterator`],
-/// `Counter`. Let's implement `ExactSizeIterator` for it as well:
+/// In the [module-level docs], we implemented an [`Iterator`], `Counter`.
+/// Let's implement `ExactSizeIterator` for it as well:
 ///
-/// [moddocs]: index.html
+/// [module-level docs]: crate::iter
 ///
 /// ```
 /// # struct Counter {
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index a75f1d5..18b4adc 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -284,6 +284,44 @@
         self.fold(None, some)
     }
 
+    /// Advances the iterator by `n` elements.
+    ///
+    /// This method will eagerly skip `n` elements by calling [`next`] up to `n`
+    /// times until [`None`] is encountered.
+    ///
+    /// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by
+    /// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number
+    /// of elements the iterator is advanced by before running out of elements (i.e. the
+    /// length of the iterator). Note that `k` is always less than `n`.
+    ///
+    /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`][Ok].
+    ///
+    /// [`next`]: Iterator::next
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_advance_by)]
+    ///
+    /// let a = [1, 2, 3, 4];
+    /// let mut iter = a.iter();
+    ///
+    /// assert_eq!(iter.advance_by(2), Ok(()));
+    /// assert_eq!(iter.next(), Some(&3));
+    /// assert_eq!(iter.advance_by(0), Ok(()));
+    /// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
+    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+        for i in 0..n {
+            self.next().ok_or(i)?;
+        }
+        Ok(())
+    }
+
     /// Returns the `n`th element of the iterator.
     ///
     /// Like most indexing operations, the count starts from zero, so `nth(0)`
@@ -325,14 +363,9 @@
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
-        while let Some(x) = self.next() {
-            if n == 0 {
-                return Some(x);
-            }
-            n -= 1;
-        }
-        None
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        self.advance_by(n).ok()?;
+        self.next()
     }
 
     /// Creates an iterator starting at the same point, but stepping by
@@ -1854,7 +1887,7 @@
         while let Some(x) = self.next() {
             accum = f(accum, x)?;
         }
-        Try::from_ok(accum)
+        try { accum }
     }
 
     /// An iterator method that applies a fallible function to each item in the
@@ -1976,6 +2009,8 @@
     /// // they're the same
     /// assert_eq!(result, result2);
     /// ```
+    #[doc(alias = "reduce")]
+    #[doc(alias = "inject")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fold<B, F>(mut self, init: B, mut f: F) -> B
@@ -3263,6 +3298,9 @@
     fn size_hint(&self) -> (usize, Option<usize>) {
         (**self).size_hint()
     }
+    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+        (**self).advance_by(n)
+    }
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
         (**self).nth(n)
     }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 30fb87b..af4b719 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -80,9 +80,11 @@
 #![feature(constctlz)]
 #![feature(const_panic)]
 #![feature(const_pin)]
-#![feature(const_fn_union)]
 #![feature(const_fn)]
-#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))]
+#![feature(const_fn_union)]
+#![cfg_attr(not(bootstrap), feature(const_impl_trait))]
+#![feature(const_fn_floating_point_arithmetic)]
+#![feature(const_fn_fn_ptr_basics)]
 #![feature(const_generics)]
 #![feature(const_option)]
 #![feature(const_precise_live_drops)]
@@ -124,13 +126,15 @@
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
+#![feature(str_split_as_str)]
+#![feature(str_split_inclusive_as_str)]
 #![feature(transparent_unions)]
+#![feature(try_blocks)]
 #![feature(unboxed_closures)]
 #![feature(unsized_locals)]
-#![feature(untagged_unions)]
+#![cfg_attr(bootstrap, feature(untagged_unions))]
 #![feature(unwind_attributes)]
 #![feature(variant_count)]
-#![cfg_attr(bootstrap, feature(doc_alias))]
 #![feature(tbm_target_feature)]
 #![feature(sse4a_target_feature)]
 #![feature(arm_target_feature)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index a1b0821..4c62c16 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1365,6 +1365,8 @@
     }
 
     /// Attribute macro applied to a static to register it as a global allocator.
+    ///
+    /// See also [`std::alloc::GlobalAlloc`](../std/alloc/trait.GlobalAlloc.html).
     #[stable(feature = "global_allocator", since = "1.28.0")]
     #[allow_internal_unstable(rustc_attrs)]
     #[rustc_builtin_macro]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index e629d28..862c452 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -246,6 +246,14 @@
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
     ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let v: MaybeUninit<Vec<u8>> = MaybeUninit::new(vec![42]);
+    /// ```
+    ///
     /// [`assume_init`]: MaybeUninit::assume_init
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
@@ -259,9 +267,15 @@
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
     ///
-    /// See the [type-level documentation][type] for some examples.
+    /// See the [type-level documentation][MaybeUninit] for some examples.
     ///
-    /// [type]: union.MaybeUninit.html
+    /// # Example
+    ///
+    /// ```
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let v: MaybeUninit<String> = MaybeUninit::uninit();
+    /// ```
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
     #[inline(always)]
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index aa1b552..a2c7da6 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -568,6 +568,7 @@
 #[inline]
 #[stable(feature = "needs_drop", since = "1.21.0")]
 #[rustc_const_stable(feature = "const_needs_drop", since = "1.36.0")]
+#[rustc_diagnostic_item = "needs_drop"]
 pub const fn needs_drop<T>() -> bool {
     intrinsics::needs_drop::<T>()
 }
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 043f0b1..bf7c87f 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -773,6 +773,35 @@
         self.to_bits().to_ne_bytes()
     }
 
+    /// Return the memory representation of this floating point number as a byte array in
+    /// native byte order.
+    ///
+    /// [`to_ne_bytes`] should be preferred over this whenever possible.
+    ///
+    /// [`to_ne_bytes`]: #method.to_ne_bytes
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(num_as_ne_bytes)]
+    /// let num = 12.5f32;
+    /// let bytes = num.as_ne_bytes();
+    /// assert_eq!(
+    ///     bytes,
+    ///     if cfg!(target_endian = "big") {
+    ///         &[0x41, 0x48, 0x00, 0x00]
+    ///     } else {
+    ///         &[0x00, 0x00, 0x48, 0x41]
+    ///     }
+    /// );
+    /// ```
+    #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+    #[inline]
+    pub fn as_ne_bytes(&self) -> &[u8; 4] {
+        // SAFETY: `f32` is a plain old datatype so we can always transmute to it
+        unsafe { &*(self as *const Self as *const _) }
+    }
+
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
     /// # Examples
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 24624b8..e31e176 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -787,6 +787,35 @@
         self.to_bits().to_ne_bytes()
     }
 
+    /// Return the memory representation of this floating point number as a byte array in
+    /// native byte order.
+    ///
+    /// [`to_ne_bytes`] should be preferred over this whenever possible.
+    ///
+    /// [`to_ne_bytes`]: #method.to_ne_bytes
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(num_as_ne_bytes)]
+    /// let num = 12.5f64;
+    /// let bytes = num.as_ne_bytes();
+    /// assert_eq!(
+    ///     bytes,
+    ///     if cfg!(target_endian = "big") {
+    ///         &[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+    ///     } else {
+    ///         &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]
+    ///     }
+    /// );
+    /// ```
+    #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+    #[inline]
+    pub fn as_ne_bytes(&self) -> &[u8; 8] {
+        // SAFETY: `f64` is a plain old datatype so we can always transmute to it
+        unsafe { &*(self as *const Self as *const _) }
+    }
+
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
     /// # Examples
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 369175f..33fa266 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2054,6 +2054,41 @@
             }
         }
 
+        doc_comment! {
+            concat!("
+Return the memory representation of this integer as a byte array in
+native byte order.
+
+[`to_ne_bytes`] should be preferred over this whenever possible.
+
+[`to_ne_bytes`]: #method.to_ne_bytes
+",
+
+"
+# Examples
+
+```
+#![feature(num_as_ne_bytes)]
+let num = ", $swap_op, stringify!($SelfT), ";
+let bytes = num.as_ne_bytes();
+assert_eq!(
+    bytes,
+    if cfg!(target_endian = \"big\") {
+        &", $be_bytes, "
+    } else {
+        &", $le_bytes, "
+    }
+);
+```"),
+            #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+            #[inline]
+            pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
+                // SAFETY: integers are plain old datatypes so we can always transmute them to
+                // arrays of bytes
+                unsafe { &*(self as *const Self as *const _) }
+            }
+        }
+
 doc_comment! {
             concat!("Create an integer value from its representation as a byte array in
 big endian.
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 234c309..0de1cc6 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1813,6 +1813,41 @@
         }
 
         doc_comment! {
+            concat!("
+Return the memory representation of this integer as a byte array in
+native byte order.
+
+[`to_ne_bytes`] should be preferred over this whenever possible.
+
+[`to_ne_bytes`]: #method.to_ne_bytes
+",
+
+"
+# Examples
+
+```
+#![feature(num_as_ne_bytes)]
+let num = ", $swap_op, stringify!($SelfT), ";
+let bytes = num.as_ne_bytes();
+assert_eq!(
+    bytes,
+    if cfg!(target_endian = \"big\") {
+        &", $be_bytes, "
+    } else {
+        &", $le_bytes, "
+    }
+);
+```"),
+            #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
+            #[inline]
+            pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
+                // SAFETY: integers are plain old datatypes so we can always transmute them to
+                // arrays of bytes
+                unsafe { &*(self as *const Self as *const _) }
+            }
+        }
+
+        doc_comment! {
             concat!("Create a native endian integer value from its representation
 as a byte array in big endian.
 ",
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index 19f86ce..92090d8 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -302,7 +302,7 @@
 #[lang = "mul"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
-    message = "cannot multiply `{Rhs}` to `{Self}`",
+    message = "cannot multiply `{Self}` by `{Rhs}`",
     label = "no implementation for `{Self} * {Rhs}`"
 )]
 #[doc(alias = "*")]
@@ -826,7 +826,7 @@
 #[lang = "mul_assign"]
 #[stable(feature = "op_assign_traits", since = "1.8.0")]
 #[rustc_on_unimplemented(
-    message = "cannot multiply-assign `{Rhs}` to `{Self}`",
+    message = "cannot multiply-assign `{Self}` by `{Rhs}`",
     label = "no implementation for `{Self} *= {Rhs}`"
 )]
 #[doc(alias = "*")]
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index b0c7dc1..3bca3ff 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -32,6 +32,20 @@
 }
 
 impl<C, B> ControlFlow<C, B> {
+    /// Returns `true` if this is a `Break` variant.
+    #[inline]
+    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    pub fn is_break(&self) -> bool {
+        matches!(*self, ControlFlow::Break(_))
+    }
+
+    /// Returns `true` if this is a `Continue` variant.
+    #[inline]
+    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+    pub fn is_continue(&self) -> bool {
+        matches!(*self, ControlFlow::Continue(_))
+    }
+
     /// Converts the `ControlFlow` into an `Option` which is `Some` if the
     /// `ControlFlow` was `Break` and `None` otherwise.
     #[inline]
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index 2eaf760..4423cfc 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -1,5 +1,9 @@
 use crate::fmt;
 use crate::hash::Hash;
+use crate::slice::index::{
+    slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail,
+    slice_start_index_overflow_fail,
+};
 
 /// An unbounded range (`..`).
 ///
@@ -19,7 +23,7 @@
 ///
 /// ```compile_fail,E0277
 /// for i in .. {
-///    // ...
+///     // ...
 /// }
 /// ```
 ///
@@ -27,12 +31,12 @@
 ///
 /// ```
 /// let arr = [0, 1, 2, 3, 4];
-/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);  // RangeFull
-/// assert_eq!(arr[ .. 3], [0,1,2    ]);
-/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
-/// assert_eq!(arr[1..  ], [  1,2,3,4]);
-/// assert_eq!(arr[1.. 3], [  1,2    ]);
-/// assert_eq!(arr[1..=3], [  1,2,3  ]);
+/// assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]); // This is the `RangeFull`
+/// assert_eq!(arr[ .. 3], [0, 1, 2      ]);
+/// assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
+/// assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
+/// assert_eq!(arr[1.. 3], [   1, 2      ]);
+/// assert_eq!(arr[1..=3], [   1, 2, 3   ]);
 /// ```
 ///
 /// [slicing index]: crate::slice::SliceIndex
@@ -52,22 +56,26 @@
 /// A (half-open) range bounded inclusively below and exclusively above
 /// (`start..end`).
 ///
-/// The `Range` `start..end` contains all values with `x >= start` and
-/// `x < end`. It is empty unless `start < end`.
+/// The range `start..end` contains all values with `start <= x < end`.
+/// It is empty if `start >= end`.
 ///
 /// # Examples
 ///
+/// The `start..end` syntax is a `Range`:
+///
 /// ```
 /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 });
 /// assert_eq!(3 + 4 + 5, (3..6).sum());
+/// ```
 ///
+/// ```
 /// let arr = [0, 1, 2, 3, 4];
-/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
-/// assert_eq!(arr[ .. 3], [0,1,2    ]);
-/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
-/// assert_eq!(arr[1..  ], [  1,2,3,4]);
-/// assert_eq!(arr[1.. 3], [  1,2    ]);  // Range
-/// assert_eq!(arr[1..=3], [  1,2,3  ]);
+/// assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
+/// assert_eq!(arr[ .. 3], [0, 1, 2      ]);
+/// assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
+/// assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
+/// assert_eq!(arr[1.. 3], [   1, 2      ]); // This is a `Range`
+/// assert_eq!(arr[1..=3], [   1, 2, 3   ]);
 /// ```
 #[lang = "Range"]
 #[doc(alias = "..")]
@@ -160,17 +168,21 @@
 ///
 /// # Examples
 ///
+/// The `start..` syntax is a `RangeFrom`:
+///
 /// ```
 /// assert_eq!((2..), std::ops::RangeFrom { start: 2 });
 /// assert_eq!(2 + 3 + 4, (2..).take(3).sum());
+/// ```
 ///
+/// ```
 /// let arr = [0, 1, 2, 3, 4];
-/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
-/// assert_eq!(arr[ .. 3], [0,1,2    ]);
-/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
-/// assert_eq!(arr[1..  ], [  1,2,3,4]);  // RangeFrom
-/// assert_eq!(arr[1.. 3], [  1,2    ]);
-/// assert_eq!(arr[1..=3], [  1,2,3  ]);
+/// assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
+/// assert_eq!(arr[ .. 3], [0, 1, 2      ]);
+/// assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
+/// assert_eq!(arr[1..  ], [   1, 2, 3, 4]); // This is a `RangeFrom`
+/// assert_eq!(arr[1.. 3], [   1, 2      ]);
+/// assert_eq!(arr[1..=3], [   1, 2, 3   ]);
 /// ```
 #[lang = "RangeFrom"]
 #[doc(alias = "..")]
@@ -244,12 +256,12 @@
 ///
 /// ```
 /// let arr = [0, 1, 2, 3, 4];
-/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
-/// assert_eq!(arr[ .. 3], [0,1,2    ]);  // RangeTo
-/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
-/// assert_eq!(arr[1..  ], [  1,2,3,4]);
-/// assert_eq!(arr[1.. 3], [  1,2    ]);
-/// assert_eq!(arr[1..=3], [  1,2,3  ]);
+/// assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
+/// assert_eq!(arr[ .. 3], [0, 1, 2      ]); // This is a `RangeTo`
+/// assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
+/// assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
+/// assert_eq!(arr[1.. 3], [   1, 2      ]);
+/// assert_eq!(arr[1..=3], [   1, 2, 3   ]);
 /// ```
 ///
 /// [slicing index]: crate::slice::SliceIndex
@@ -310,17 +322,21 @@
 ///
 /// # Examples
 ///
+/// The `start..=end` syntax is a `RangeInclusive`:
+///
 /// ```
 /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5));
 /// assert_eq!(3 + 4 + 5, (3..=5).sum());
+/// ```
 ///
+/// ```
 /// let arr = [0, 1, 2, 3, 4];
-/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
-/// assert_eq!(arr[ .. 3], [0,1,2    ]);
-/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
-/// assert_eq!(arr[1..  ], [  1,2,3,4]);
-/// assert_eq!(arr[1.. 3], [  1,2    ]);
-/// assert_eq!(arr[1..=3], [  1,2,3  ]);  // RangeInclusive
+/// assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
+/// assert_eq!(arr[ .. 3], [0, 1, 2      ]);
+/// assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
+/// assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
+/// assert_eq!(arr[1.. 3], [   1, 2      ]);
+/// assert_eq!(arr[1..=3], [   1, 2, 3   ]); // This is a `RangeInclusive`
 /// ```
 #[lang = "RangeInclusive"]
 #[doc(alias = "..=")]
@@ -534,12 +550,12 @@
 ///
 /// ```
 /// let arr = [0, 1, 2, 3, 4];
-/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
-/// assert_eq!(arr[ .. 3], [0,1,2    ]);
-/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);  // RangeToInclusive
-/// assert_eq!(arr[1..  ], [  1,2,3,4]);
-/// assert_eq!(arr[1.. 3], [  1,2    ]);
-/// assert_eq!(arr[1..=3], [  1,2,3  ]);
+/// assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
+/// assert_eq!(arr[ .. 3], [0, 1, 2      ]);
+/// assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]); // This is a `RangeToInclusive`
+/// assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
+/// assert_eq!(arr[1.. 3], [   1, 2      ]);
+/// assert_eq!(arr[1..=3], [   1, 2, 3   ]);
 /// ```
 ///
 /// [slicing index]: crate::slice::SliceIndex
@@ -661,9 +677,9 @@
     }
 }
 
-#[stable(feature = "collections_range", since = "1.28.0")]
 /// `RangeBounds` is implemented by Rust's built-in range types, produced
 /// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`.
+#[stable(feature = "collections_range", since = "1.28.0")]
 pub trait RangeBounds<T: ?Sized> {
     /// Start index bound.
     ///
@@ -701,6 +717,92 @@
     #[stable(feature = "collections_range", since = "1.28.0")]
     fn end_bound(&self) -> Bound<&T>;
 
+    /// Performs bounds-checking of this range.
+    ///
+    /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and
+    /// [`slice::get_unchecked_mut`] for slices of the given length.
+    ///
+    /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
+    /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
+    ///
+    /// # Panics
+    ///
+    /// Panics if the range would be out of bounds.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(range_bounds_assert_len)]
+    ///
+    /// use std::ops::RangeBounds;
+    ///
+    /// let v = [10, 40, 30];
+    /// assert_eq!(1..2, (1..2).assert_len(v.len()));
+    /// assert_eq!(0..2, (..2).assert_len(v.len()));
+    /// assert_eq!(1..3, (1..).assert_len(v.len()));
+    /// ```
+    ///
+    /// Panics when [`Index::index`] would panic:
+    ///
+    /// ```should_panic
+    /// #![feature(range_bounds_assert_len)]
+    ///
+    /// use std::ops::RangeBounds;
+    ///
+    /// (2..1).assert_len(3);
+    /// ```
+    ///
+    /// ```should_panic
+    /// #![feature(range_bounds_assert_len)]
+    ///
+    /// use std::ops::RangeBounds;
+    ///
+    /// (1..4).assert_len(3);
+    /// ```
+    ///
+    /// ```should_panic
+    /// #![feature(range_bounds_assert_len)]
+    ///
+    /// use std::ops::RangeBounds;
+    ///
+    /// (1..=usize::MAX).assert_len(3);
+    /// ```
+    ///
+    /// [`Index::index`]: crate::ops::Index::index
+    #[track_caller]
+    #[unstable(feature = "range_bounds_assert_len", issue = "76393")]
+    fn assert_len(self, len: usize) -> Range<usize>
+    where
+        Self: RangeBounds<usize>,
+    {
+        let start: Bound<&usize> = self.start_bound();
+        let start = match start {
+            Bound::Included(&start) => start,
+            Bound::Excluded(start) => {
+                start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
+            }
+            Bound::Unbounded => 0,
+        };
+
+        let end: Bound<&usize> = self.end_bound();
+        let end = match end {
+            Bound::Included(end) => {
+                end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
+            }
+            Bound::Excluded(&end) => end,
+            Bound::Unbounded => len,
+        };
+
+        if start > end {
+            slice_index_order_fail(start, end);
+        }
+        if end > len {
+            slice_end_index_len_fail(end, len);
+        }
+
+        Range { start, end }
+    }
+
     /// Returns `true` if `item` is contained in the range.
     ///
     /// # Examples
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 0cfb4af..825144e 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -141,6 +141,9 @@
 //! ```
 //!
 //! [`Box<T>`]: ../../std/boxed/struct.Box.html
+//! [`Box<U>`]: ../../std/boxed/struct.Box.html
+//! [`num::NonZero*`]: crate::num
+//! [`ptr::NonNull<U>`]: crate::ptr::NonNull
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -684,6 +687,7 @@
     /// assert_eq!(Some(4).filter(is_even), Some(4));
     /// ```
     ///
+    /// [`Some(t)`]: Some
     #[inline]
     #[stable(feature = "option_filter", since = "1.27.0")]
     pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 9f0284d..0b9c733 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -781,6 +781,34 @@
     }
 }
 
+impl<T: ?Sized> Pin<&'static T> {
+    /// Get a pinned reference from a static reference.
+    ///
+    /// This is safe, because `T` is borrowed for the `'static` lifetime, which
+    /// never ends.
+    #[unstable(feature = "pin_static_ref", issue = "78186")]
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    pub const fn static_ref(r: &'static T) -> Pin<&'static T> {
+        // SAFETY: The 'static borrow guarantees the data will not be
+        // moved/invalidated until it gets dropped (which is never).
+        unsafe { Pin::new_unchecked(r) }
+    }
+}
+
+impl<T: ?Sized> Pin<&'static mut T> {
+    /// Get a pinned mutable reference from a static mutable reference.
+    ///
+    /// This is safe, because `T` is borrowed for the `'static` lifetime, which
+    /// never ends.
+    #[unstable(feature = "pin_static_ref", issue = "78186")]
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    pub const fn static_mut(r: &'static mut T) -> Pin<&'static mut T> {
+        // SAFETY: The 'static borrow guarantees the data will not be
+        // moved/invalidated until it gets dropped (which is never).
+        unsafe { Pin::new_unchecked(r) }
+    }
+}
+
 #[stable(feature = "pin", since = "1.33.0")]
 impl<P: Deref> Deref for Pin<P> {
     type Target = P::Target;
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 92c4f2c..bca3be5 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -229,6 +229,16 @@
     pub(crate) len: usize,
 }
 
+// Manual impl needed to avoid `T: Clone` bound.
+impl<T> Clone for FatPtr<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+// Manual impl needed to avoid `T: Copy` bound.
+impl<T> Copy for FatPtr<T> {}
+
 /// Forms a raw slice from a pointer and a length.
 ///
 /// The `len` argument is the number of **elements**, not the number of bytes.
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 87a59c8..5dc7171 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -448,7 +448,7 @@
     /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized.
     /// # #[allow(unused_variables)]
     /// let slice: &mut [MaybeUninit<u8>] = unsafe { memory.as_uninit_slice_mut() };
-    /// # Ok::<_, std::alloc::AllocErr>(())
+    /// # Ok::<_, std::alloc::AllocError>(())
     /// ```
     #[inline]
     #[unstable(feature = "ptr_as_uninit", issue = "75402")]
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 5cec183..b6d9f13 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -233,7 +233,7 @@
 
 /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
 ///
-/// See the [`std::result`](index.html) module documentation for details.
+/// See the [module documentation](self) for details.
 #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
 #[must_use = "this `Result` may be an `Err` variant, which should be handled"]
 #[rustc_diagnostic_item = "result_type"]
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 27a358b..ed26c59 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -268,12 +268,14 @@
 }
 
 impl SliceContains for u8 {
+    #[inline]
     fn slice_contains(&self, x: &[Self]) -> bool {
         memchr::memchr(*self, x).is_some()
     }
 }
 
 impl SliceContains for i8 {
+    #[inline]
     fn slice_contains(&self, x: &[Self]) -> bool {
         let byte = *self as u8;
         // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()`
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 16fcb62..f1f21c1 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -1,6 +1,6 @@
 //! Indexing implementations for `[T]`.
 
-use crate::ops::{self, Bound, Range, RangeBounds};
+use crate::ops;
 use crate::ptr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -37,104 +37,31 @@
 #[inline(never)]
 #[cold]
 #[track_caller]
-pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
+pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
     panic!("range end index {} out of range for slice of length {}", index, len);
 }
 
 #[inline(never)]
 #[cold]
 #[track_caller]
-pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! {
+pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! {
     panic!("slice index starts at {} but ends at {}", index, end);
 }
 
 #[inline(never)]
 #[cold]
 #[track_caller]
-pub(super) fn slice_start_index_overflow_fail() -> ! {
+pub(crate) fn slice_start_index_overflow_fail() -> ! {
     panic!("attempted to index slice from after maximum usize");
 }
 
 #[inline(never)]
 #[cold]
 #[track_caller]
-pub(super) fn slice_end_index_overflow_fail() -> ! {
+pub(crate) fn slice_end_index_overflow_fail() -> ! {
     panic!("attempted to index slice up to maximum usize");
 }
 
-/// Performs bounds-checking of the given range.
-/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]
-/// for slices of the given length.
-///
-/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
-/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
-///
-/// # Panics
-///
-/// Panics if the range is out of bounds.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(slice_check_range)]
-/// use std::slice;
-///
-/// let v = [10, 40, 30];
-/// assert_eq!(1..2, slice::check_range(v.len(), 1..2));
-/// assert_eq!(0..2, slice::check_range(v.len(), ..2));
-/// assert_eq!(1..3, slice::check_range(v.len(), 1..));
-/// ```
-///
-/// Panics when [`Index::index`] would panic:
-///
-/// ```should_panic
-/// #![feature(slice_check_range)]
-///
-/// std::slice::check_range(3, 2..1);
-/// ```
-///
-/// ```should_panic
-/// #![feature(slice_check_range)]
-///
-/// std::slice::check_range(3, 1..4);
-/// ```
-///
-/// ```should_panic
-/// #![feature(slice_check_range)]
-///
-/// std::slice::check_range(3, 1..=usize::MAX);
-/// ```
-///
-/// [`Index::index`]: ops::Index::index
-#[track_caller]
-#[unstable(feature = "slice_check_range", issue = "76393")]
-pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> {
-    let start = match range.start_bound() {
-        Bound::Included(&start) => start,
-        Bound::Excluded(start) => {
-            start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
-        }
-        Bound::Unbounded => 0,
-    };
-
-    let end = match range.end_bound() {
-        Bound::Included(end) => {
-            end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
-        }
-        Bound::Excluded(&end) => end,
-        Bound::Unbounded => len,
-    };
-
-    if start > end {
-        slice_index_order_fail(start, end);
-    }
-    if end > len {
-        slice_end_index_len_fail(end, len);
-    }
-
-    Range { start, end }
-}
-
 mod private_slice_index {
     use super::ops;
     #[stable(feature = "slice_get_slice", since = "1.28.0")]
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 793cbf9..24f955a 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -10,6 +10,7 @@
 use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
 use crate::marker::{PhantomData, Send, Sized, Sync};
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::ptr::NonNull;
 
 use super::{from_raw_parts, from_raw_parts_mut};
@@ -1187,12 +1188,12 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Windows<'a, T: 'a> {
     v: &'a [T],
-    size: usize,
+    size: NonZeroUsize,
 }
 
 impl<'a, T: 'a> Windows<'a, T> {
     #[inline]
-    pub(super) fn new(slice: &'a [T], size: usize) -> Self {
+    pub(super) fn new(slice: &'a [T], size: NonZeroUsize) -> Self {
         Self { v: slice, size }
     }
 }
@@ -1211,10 +1212,10 @@
 
     #[inline]
     fn next(&mut self) -> Option<&'a [T]> {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             None
         } else {
-            let ret = Some(&self.v[..self.size]);
+            let ret = Some(&self.v[..self.size.get()]);
             self.v = &self.v[1..];
             ret
         }
@@ -1222,10 +1223,10 @@
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             (0, Some(0))
         } else {
-            let size = self.v.len() - self.size + 1;
+            let size = self.v.len() - self.size.get() + 1;
             (size, Some(size))
         }
     }
@@ -1237,7 +1238,7 @@
 
     #[inline]
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        let (end, overflow) = self.size.overflowing_add(n);
+        let (end, overflow) = self.size.get().overflowing_add(n);
         if end > self.v.len() || overflow {
             self.v = &[];
             None
@@ -1250,10 +1251,10 @@
 
     #[inline]
     fn last(self) -> Option<Self::Item> {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             None
         } else {
-            let start = self.v.len() - self.size;
+            let start = self.v.len() - self.size.get();
             Some(&self.v[start..])
         }
     }
@@ -1264,7 +1265,7 @@
         // which means that `i` cannot overflow an `isize`, and the
         // slice created by `from_raw_parts` is a subslice of `self.v`
         // thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
-        unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) }
+        unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size.get()) }
     }
 }
 
@@ -1272,10 +1273,10 @@
 impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
     #[inline]
     fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             None
         } else {
-            let ret = Some(&self.v[self.v.len() - self.size..]);
+            let ret = Some(&self.v[self.v.len() - self.size.get()..]);
             self.v = &self.v[..self.v.len() - 1];
             ret
         }
@@ -1284,11 +1285,11 @@
     #[inline]
     fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
         let (end, overflow) = self.v.len().overflowing_sub(n);
-        if end < self.size || overflow {
+        if end < self.size.get() || overflow {
             self.v = &[];
             None
         } else {
-            let ret = &self.v[end - self.size..end];
+            let ret = &self.v[end - self.size.get()..end];
             self.v = &self.v[..end - 1];
             Some(ret)
         }
diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs
index 3b13ed5..0c0f175 100644
--- a/library/core/src/slice/memchr.rs
+++ b/library/core/src/slice/memchr.rs
@@ -12,6 +12,7 @@
 // Use truncation.
 const LO_USIZE: usize = LO_U64 as usize;
 const HI_USIZE: usize = HI_U64 as usize;
+const USIZE_BYTES: usize = mem::size_of::<usize>();
 
 /// Returns `true` if `x` contains any zero byte.
 ///
@@ -38,19 +39,29 @@
 }
 
 /// Returns the first index matching the byte `x` in `text`.
+#[inline]
 pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
+    // Fast path for small slices
+    if text.len() < 2 * USIZE_BYTES {
+        return text.iter().position(|elt| *elt == x);
+    }
+
+    memchr_general_case(x, text)
+}
+
+fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
     // Scan for a single byte value by reading two `usize` words at a time.
     //
     // Split `text` in three parts
     // - unaligned initial part, before the first word aligned address in text
     // - body, scan by 2 words at a time
     // - the last remaining part, < 2 word size
-    let len = text.len();
-    let ptr = text.as_ptr();
-    let usize_bytes = mem::size_of::<usize>();
 
     // search up to an aligned boundary
-    let mut offset = ptr.align_offset(usize_bytes);
+    let len = text.len();
+    let ptr = text.as_ptr();
+    let mut offset = ptr.align_offset(USIZE_BYTES);
+
     if offset > 0 {
         offset = cmp::min(offset, len);
         if let Some(index) = text[..offset].iter().position(|elt| *elt == x) {
@@ -60,22 +71,19 @@
 
     // search the body of the text
     let repeated_x = repeat_byte(x);
+    while offset <= len - 2 * USIZE_BYTES {
+        unsafe {
+            let u = *(ptr.add(offset) as *const usize);
+            let v = *(ptr.add(offset + USIZE_BYTES) as *const usize);
 
-    if len >= 2 * usize_bytes {
-        while offset <= len - 2 * usize_bytes {
-            unsafe {
-                let u = *(ptr.add(offset) as *const usize);
-                let v = *(ptr.add(offset + usize_bytes) as *const usize);
-
-                // break if there is a matching byte
-                let zu = contains_zero_byte(u ^ repeated_x);
-                let zv = contains_zero_byte(v ^ repeated_x);
-                if zu || zv {
-                    break;
-                }
+            // break if there is a matching byte
+            let zu = contains_zero_byte(u ^ repeated_x);
+            let zv = contains_zero_byte(v ^ repeated_x);
+            if zu || zv {
+                break;
             }
-            offset += usize_bytes * 2;
         }
+        offset += USIZE_BYTES * 2;
     }
 
     // Find the byte after the point the body loop stopped.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 12dcd6c..376ad32 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -11,6 +11,7 @@
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::marker::Copy;
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::ops::{FnMut, Range, RangeBounds};
 use crate::option::Option;
 use crate::option::Option::{None, Some};
@@ -28,7 +29,7 @@
 
 mod ascii;
 mod cmp;
-mod index;
+pub(crate) mod index;
 mod iter;
 mod raw;
 mod rotate;
@@ -72,9 +73,6 @@
 #[stable(feature = "slice_get_slice", since = "1.28.0")]
 pub use index::SliceIndex;
 
-#[unstable(feature = "slice_check_range", issue = "76393")]
-pub use index::check_range;
-
 #[lang = "slice"]
 #[cfg(not(test))]
 impl<T> [T] {
@@ -458,8 +456,6 @@
     /// element of this slice:
     ///
     /// ```
-    /// #![feature(slice_ptr_range)]
-    ///
     /// let a = [1, 2, 3];
     /// let x = &a[1] as *const _;
     /// let y = &5 as *const _;
@@ -469,7 +465,7 @@
     /// ```
     ///
     /// [`as_ptr`]: #method.as_ptr
-    #[unstable(feature = "slice_ptr_range", issue = "65807")]
+    #[stable(feature = "slice_ptr_range", since = "1.48.0")]
     #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
     pub const fn as_ptr_range(&self) -> Range<*const T> {
@@ -511,7 +507,7 @@
     /// common in C++.
     ///
     /// [`as_mut_ptr`]: #method.as_mut_ptr
-    #[unstable(feature = "slice_ptr_range", issue = "65807")]
+    #[stable(feature = "slice_ptr_range", since = "1.48.0")]
     #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
     #[inline]
     pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
@@ -730,7 +726,7 @@
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn windows(&self, size: usize) -> Windows<'_, T> {
-        assert_ne!(size, 0);
+        let size = NonZeroUsize::new(size).expect("size is zero");
         Windows::new(self, size)
     }
 
@@ -1636,6 +1632,7 @@
     /// assert!(!v.iter().any(|e| e == "hi"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
     pub fn contains(&self, x: &T) -> bool
     where
         T: PartialEq,
@@ -1948,10 +1945,10 @@
     ///
     /// The comparator function must define a total ordering for the elements in the slice. If
     /// the ordering is not total, the order of the elements is unspecified. An order is a
-    /// total order if it is (for all a, b and c):
+    /// total order if it is (for all `a`, `b` and `c`):
     ///
-    /// * total and antisymmetric: exactly one of a < b, a == b or a > b is true; and
-    /// * transitive, a < b and b < c implies a < c. The same must hold for both == and >.
+    /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
+    /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
     ///
     /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
     /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`.
@@ -2035,6 +2032,50 @@
     }
 
     /// Reorder the slice such that the element at `index` is at its final sorted position.
+    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable() instead")]
+    #[inline]
+    pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
+    where
+        T: Ord,
+    {
+        self.select_nth_unstable(index)
+    }
+
+    /// Reorder the slice with a comparator function such that the element at `index` is at its
+    /// final sorted position.
+    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[rustc_deprecated(since = "1.49.0", reason = "use select_nth_unstable_by() instead")]
+    #[inline]
+    pub fn partition_at_index_by<F>(
+        &mut self,
+        index: usize,
+        compare: F,
+    ) -> (&mut [T], &mut T, &mut [T])
+    where
+        F: FnMut(&T, &T) -> Ordering,
+    {
+        self.select_nth_unstable_by(index, compare)
+    }
+
+    /// Reorder the slice with a key extraction function such that the element at `index` is at its
+    /// final sorted position.
+    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable_by_key() instead")]
+    #[inline]
+    pub fn partition_at_index_by_key<K, F>(
+        &mut self,
+        index: usize,
+        f: F,
+    ) -> (&mut [T], &mut T, &mut [T])
+    where
+        F: FnMut(&T) -> K,
+        K: Ord,
+    {
+        self.select_nth_unstable_by_key(index, f)
+    }
+
+    /// Reorder the slice such that the element at `index` is at its final sorted position.
     ///
     /// This reordering has the additional property that any value at position `i < index` will be
     /// less than or equal to any value at a position `j > index`. Additionally, this reordering is
@@ -2058,12 +2099,10 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_partition_at_index)]
-    ///
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
     /// // Find the median
-    /// v.partition_at_index(2);
+    /// v.select_nth_unstable(2);
     ///
     /// // We are only guaranteed the slice will be one of the following, based on the way we sort
     /// // about the specified index.
@@ -2072,9 +2111,9 @@
     ///         v == [-3, -5, 1, 4, 2] ||
     ///         v == [-5, -3, 1, 4, 2]);
     /// ```
-    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
-    pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
+    pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
     where
         T: Ord,
     {
@@ -2108,12 +2147,10 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_partition_at_index)]
-    ///
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
     /// // Find the median as if the slice were sorted in descending order.
-    /// v.partition_at_index_by(2, |a, b| b.cmp(a));
+    /// v.select_nth_unstable_by(2, |a, b| b.cmp(a));
     ///
     /// // We are only guaranteed the slice will be one of the following, based on the way we sort
     /// // about the specified index.
@@ -2122,9 +2159,9 @@
     ///         v == [4, 2, 1, -5, -3] ||
     ///         v == [4, 2, 1, -3, -5]);
     /// ```
-    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
-    pub fn partition_at_index_by<F>(
+    pub fn select_nth_unstable_by<F>(
         &mut self,
         index: usize,
         mut compare: F,
@@ -2162,12 +2199,10 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_partition_at_index)]
-    ///
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
     /// // Return the median as if the array were sorted according to absolute value.
-    /// v.partition_at_index_by_key(2, |a| a.abs());
+    /// v.select_nth_unstable_by_key(2, |a| a.abs());
     ///
     /// // We are only guaranteed the slice will be one of the following, based on the way we sort
     /// // about the specified index.
@@ -2176,9 +2211,9 @@
     ///         v == [2, 1, -3, 4, -5] ||
     ///         v == [2, 1, -3, -5, 4]);
     /// ```
-    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
-    pub fn partition_at_index_by_key<K, F>(
+    pub fn select_nth_unstable_by_key<K, F>(
         &mut self,
         index: usize,
         mut f: F,
@@ -2676,7 +2711,7 @@
     where
         T: Copy,
     {
-        let Range { start: src_start, end: src_end } = check_range(self.len(), src);
+        let Range { start: src_start, end: src_end } = src.assert_len(self.len());
         let count = src_end - src_start;
         assert!(dest <= self.len() - count, "dest is out of bounds");
         // SAFETY: the conditions for `ptr::copy` have all been checked above,
diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs
new file mode 100644
index 0000000..de2a93f
--- /dev/null
+++ b/library/core/src/str/converts.rs
@@ -0,0 +1,192 @@
+//! Ways to create a `str` from bytes slice.
+
+use crate::mem;
+
+use super::validations::run_utf8_validation;
+use super::Utf8Error;
+
+/// Converts a slice of bytes to a string slice.
+///
+/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice
+/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between
+/// the two. Not all byte slices are valid string slices, however: [`&str`] requires
+/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid
+/// UTF-8, and then does the conversion.
+///
+/// [`&str`]: str
+/// [byteslice]: ../../std/primitive.slice.html
+///
+/// If you are sure that the byte slice is valid UTF-8, and you don't want to
+/// incur the overhead of the validity check, there is an unsafe version of
+/// this function, [`from_utf8_unchecked`], which has the same
+/// behavior but skips the check.
+///
+/// If you need a `String` instead of a `&str`, consider
+/// [`String::from_utf8`][string].
+///
+/// [string]: ../../std/string/struct.String.html#method.from_utf8
+///
+/// Because you can stack-allocate a `[u8; N]`, and you can take a
+/// [`&[u8]`][byteslice] of it, this function is one way to have a
+/// stack-allocated string. There is an example of this in the
+/// examples section below.
+///
+/// [byteslice]: ../../std/primitive.slice.html
+///
+/// # Errors
+///
+/// Returns `Err` if the slice is not UTF-8 with a description as to why the
+/// provided slice is not UTF-8.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // some bytes, in a vector
+/// let sparkle_heart = vec![240, 159, 146, 150];
+///
+/// // We know these bytes are valid, so just use `unwrap()`.
+/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap();
+///
+/// assert_eq!("💖", sparkle_heart);
+/// ```
+///
+/// Incorrect bytes:
+///
+/// ```
+/// use std::str;
+///
+/// // some invalid bytes, in a vector
+/// let sparkle_heart = vec![0, 159, 146, 150];
+///
+/// assert!(str::from_utf8(&sparkle_heart).is_err());
+/// ```
+///
+/// See the docs for [`Utf8Error`] for more details on the kinds of
+/// errors that can be returned.
+///
+/// A "stack allocated string":
+///
+/// ```
+/// use std::str;
+///
+/// // some bytes, in a stack-allocated array
+/// let sparkle_heart = [240, 159, 146, 150];
+///
+/// // We know these bytes are valid, so just use `unwrap()`.
+/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap();
+///
+/// assert_eq!("💖", sparkle_heart);
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
+    run_utf8_validation(v)?;
+    // SAFETY: Just ran validation.
+    Ok(unsafe { from_utf8_unchecked(v) })
+}
+
+/// Converts a mutable slice of bytes to a mutable string slice.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // "Hello, Rust!" as a mutable vector
+/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
+///
+/// // As we know these bytes are valid, we can use `unwrap()`
+/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap();
+///
+/// assert_eq!("Hello, Rust!", outstr);
+/// ```
+///
+/// Incorrect bytes:
+///
+/// ```
+/// use std::str;
+///
+/// // Some invalid bytes in a mutable vector
+/// let mut invalid = vec![128, 223];
+///
+/// assert!(str::from_utf8_mut(&mut invalid).is_err());
+/// ```
+/// See the docs for [`Utf8Error`] for more details on the kinds of
+/// errors that can be returned.
+#[stable(feature = "str_mut_extras", since = "1.20.0")]
+pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
+    run_utf8_validation(v)?;
+    // SAFETY: Just ran validation.
+    Ok(unsafe { from_utf8_unchecked_mut(v) })
+}
+
+/// Converts a slice of bytes to a string slice without checking
+/// that the string contains valid UTF-8.
+///
+/// See the safe version, [`from_utf8`], for more information.
+///
+/// # Safety
+///
+/// This function is unsafe because it does not check that the bytes passed to
+/// it are valid UTF-8. If this constraint is violated, undefined behavior
+/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8.
+///
+/// [`&str`]: str
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // some bytes, in a vector
+/// let sparkle_heart = vec![240, 159, 146, 150];
+///
+/// let sparkle_heart = unsafe {
+///     str::from_utf8_unchecked(&sparkle_heart)
+/// };
+///
+/// assert_eq!("💖", sparkle_heart);
+/// ```
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")]
+#[allow_internal_unstable(const_fn_transmute)]
+pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
+    // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8.
+    // Also relies on `&str` and `&[u8]` having the same layout.
+    unsafe { mem::transmute(v) }
+}
+
+/// Converts a slice of bytes to a string slice without checking
+/// that the string contains valid UTF-8; mutable version.
+///
+/// See the immutable version, [`from_utf8_unchecked()`] for more information.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// let mut heart = vec![240, 159, 146, 150];
+/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
+///
+/// assert_eq!("💖", heart);
+/// ```
+#[inline]
+#[stable(feature = "str_mut_extras", since = "1.20.0")]
+pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
+    // SAFETY: the caller must guarantee that the bytes `v`
+    // are valid UTF-8, thus the cast to `*mut str` is safe.
+    // Also, the pointer dereference is safe because that pointer
+    // comes from a reference which is guaranteed to be valid for writes.
+    unsafe { &mut *(v as *mut [u8] as *mut str) }
+}
diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs
new file mode 100644
index 0000000..427f720
--- /dev/null
+++ b/library/core/src/str/error.rs
@@ -0,0 +1,129 @@
+//! Defines utf8 error type.
+
+use crate::fmt;
+
+/// Errors which can occur when attempting to interpret a sequence of [`u8`]
+/// as a string.
+///
+/// As such, the `from_utf8` family of functions and methods for both [`String`]s
+/// and [`&str`]s make use of this error, for example.
+///
+/// [`String`]: ../../std/string/struct.String.html#method.from_utf8
+/// [`&str`]: super::from_utf8
+///
+/// # Examples
+///
+/// This error type’s methods can be used to create functionality
+/// similar to `String::from_utf8_lossy` without allocating heap memory:
+///
+/// ```
+/// fn from_utf8_lossy<F>(mut input: &[u8], mut push: F) where F: FnMut(&str) {
+///     loop {
+///         match std::str::from_utf8(input) {
+///             Ok(valid) => {
+///                 push(valid);
+///                 break
+///             }
+///             Err(error) => {
+///                 let (valid, after_valid) = input.split_at(error.valid_up_to());
+///                 unsafe {
+///                     push(std::str::from_utf8_unchecked(valid))
+///                 }
+///                 push("\u{FFFD}");
+///
+///                 if let Some(invalid_sequence_length) = error.error_len() {
+///                     input = &after_valid[invalid_sequence_length..]
+///                 } else {
+///                     break
+///                 }
+///             }
+///         }
+///     }
+/// }
+/// ```
+#[derive(Copy, Eq, PartialEq, Clone, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Utf8Error {
+    pub(super) valid_up_to: usize,
+    pub(super) error_len: Option<u8>,
+}
+
+impl Utf8Error {
+    /// Returns the index in the given string up to which valid UTF-8 was
+    /// verified.
+    ///
+    /// It is the maximum index such that `from_utf8(&input[..index])`
+    /// would return `Ok(_)`.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::str;
+    ///
+    /// // some invalid bytes, in a vector
+    /// let sparkle_heart = vec![0, 159, 146, 150];
+    ///
+    /// // std::str::from_utf8 returns a Utf8Error
+    /// let error = str::from_utf8(&sparkle_heart).unwrap_err();
+    ///
+    /// // the second byte is invalid here
+    /// assert_eq!(1, error.valid_up_to());
+    /// ```
+    #[stable(feature = "utf8_error", since = "1.5.0")]
+    pub fn valid_up_to(&self) -> usize {
+        self.valid_up_to
+    }
+
+    /// Provides more information about the failure:
+    ///
+    /// * `None`: the end of the input was reached unexpectedly.
+    ///   `self.valid_up_to()` is 1 to 3 bytes from the end of the input.
+    ///   If a byte stream (such as a file or a network socket) is being decoded incrementally,
+    ///   this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks.
+    ///
+    /// * `Some(len)`: an unexpected byte was encountered.
+    ///   The length provided is that of the invalid byte sequence
+    ///   that starts at the index given by `valid_up_to()`.
+    ///   Decoding should resume after that sequence
+    ///   (after inserting a [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]) in case of
+    ///   lossy decoding.
+    ///
+    /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
+    #[stable(feature = "utf8_error_error_len", since = "1.20.0")]
+    pub fn error_len(&self) -> Option<usize> {
+        self.error_len.map(|len| len as usize)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Utf8Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(error_len) = self.error_len {
+            write!(
+                f,
+                "invalid utf-8 sequence of {} bytes from index {}",
+                error_len, self.valid_up_to
+            )
+        } else {
+            write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to)
+        }
+    }
+}
+
+/// An error returned when parsing a `bool` using [`from_str`] fails
+///
+/// [`from_str`]: super::FromStr::from_str
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct ParseBoolError {
+    pub(super) _priv: (),
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for ParseBoolError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "provided string was not `true` or `false`".fmt(f)
+    }
+}
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
new file mode 100644
index 0000000..bee86df
--- /dev/null
+++ b/library/core/src/str/iter.rs
@@ -0,0 +1,1419 @@
+//! Iterators for `str` methods.
+
+use crate::char;
+use crate::fmt::{self, Write};
+use crate::iter::TrustedRandomAccess;
+use crate::iter::{Chain, FlatMap, Flatten};
+use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen};
+use crate::ops::Try;
+use crate::option;
+use crate::slice::{self, Split as SliceSplit};
+
+use super::from_utf8_unchecked;
+use super::pattern::Pattern;
+use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
+use super::validations::{next_code_point, next_code_point_reverse, utf8_is_cont_byte};
+use super::LinesAnyMap;
+use super::{BytesIsNotEmpty, UnsafeBytesToStr};
+use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode};
+use super::{IsAsciiWhitespace, IsNotEmpty, IsWhitespace};
+
+/// An iterator over the [`char`]s of a string slice.
+///
+///
+/// This struct is created by the [`chars`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`char`]: prim@char
+/// [`chars`]: str::chars
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Chars<'a> {
+    pub(super) iter: slice::Iter<'a, u8>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for Chars<'a> {
+    type Item = char;
+
+    #[inline]
+    fn next(&mut self) -> Option<char> {
+        next_code_point(&mut self.iter).map(|ch| {
+            // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value.
+            unsafe { char::from_u32_unchecked(ch) }
+        })
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        // length in `char` is equal to the number of non-continuation bytes
+        let bytes_len = self.iter.len();
+        let mut cont_bytes = 0;
+        for &byte in self.iter {
+            cont_bytes += utf8_is_cont_byte(byte) as usize;
+        }
+        bytes_len - cont_bytes
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let len = self.iter.len();
+        // `(len + 3)` can't overflow, because we know that the `slice::Iter`
+        // belongs to a slice in memory which has a maximum length of
+        // `isize::MAX` (that's well below `usize::MAX`).
+        ((len + 3) / 4, Some(len))
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<char> {
+        // No need to go through the entire string.
+        self.next_back()
+    }
+}
+
+#[stable(feature = "chars_debug_impl", since = "1.38.0")]
+impl fmt::Debug for Chars<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Chars(")?;
+        f.debug_list().entries(self.clone()).finish()?;
+        write!(f, ")")?;
+        Ok(())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> DoubleEndedIterator for Chars<'a> {
+    #[inline]
+    fn next_back(&mut self) -> Option<char> {
+        next_code_point_reverse(&mut self.iter).map(|ch| {
+            // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value.
+            unsafe { char::from_u32_unchecked(ch) }
+        })
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for Chars<'_> {}
+
+impl<'a> Chars<'a> {
+    /// Views the underlying data as a subslice of the original data.
+    ///
+    /// This has the same lifetime as the original slice, and so the
+    /// iterator can continue to be used while this exists.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut chars = "abc".chars();
+    ///
+    /// assert_eq!(chars.as_str(), "abc");
+    /// chars.next();
+    /// assert_eq!(chars.as_str(), "bc");
+    /// chars.next();
+    /// chars.next();
+    /// assert_eq!(chars.as_str(), "");
+    /// ```
+    #[stable(feature = "iter_to_slice", since = "1.4.0")]
+    #[inline]
+    pub fn as_str(&self) -> &'a str {
+        // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8.
+        unsafe { from_utf8_unchecked(self.iter.as_slice()) }
+    }
+}
+
+/// An iterator over the [`char`]s of a string slice, and their positions.
+///
+/// This struct is created by the [`char_indices`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`char`]: prim@char
+/// [`char_indices`]: str::char_indices
+#[derive(Clone, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct CharIndices<'a> {
+    pub(super) front_offset: usize,
+    pub(super) iter: Chars<'a>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for CharIndices<'a> {
+    type Item = (usize, char);
+
+    #[inline]
+    fn next(&mut self) -> Option<(usize, char)> {
+        let pre_len = self.iter.iter.len();
+        match self.iter.next() {
+            None => None,
+            Some(ch) => {
+                let index = self.front_offset;
+                let len = self.iter.iter.len();
+                self.front_offset += pre_len - len;
+                Some((index, ch))
+            }
+        }
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.iter.count()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<(usize, char)> {
+        // No need to go through the entire string.
+        self.next_back()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> DoubleEndedIterator for CharIndices<'a> {
+    #[inline]
+    fn next_back(&mut self) -> Option<(usize, char)> {
+        self.iter.next_back().map(|ch| {
+            let index = self.front_offset + self.iter.iter.len();
+            (index, ch)
+        })
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for CharIndices<'_> {}
+
+impl<'a> CharIndices<'a> {
+    /// Views the underlying data as a subslice of the original data.
+    ///
+    /// This has the same lifetime as the original slice, and so the
+    /// iterator can continue to be used while this exists.
+    #[stable(feature = "iter_to_slice", since = "1.4.0")]
+    #[inline]
+    pub fn as_str(&self) -> &'a str {
+        self.iter.as_str()
+    }
+}
+
+/// An iterator over the bytes of a string slice.
+///
+/// This struct is created by the [`bytes`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`bytes`]: str::bytes
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone, Debug)]
+pub struct Bytes<'a>(pub(super) Copied<slice::Iter<'a, u8>>);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Iterator for Bytes<'_> {
+    type Item = u8;
+
+    #[inline]
+    fn next(&mut self) -> Option<u8> {
+        self.0.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.0.count()
+    }
+
+    #[inline]
+    fn last(self) -> Option<Self::Item> {
+        self.0.last()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        self.0.nth(n)
+    }
+
+    #[inline]
+    fn all<F>(&mut self, f: F) -> bool
+    where
+        F: FnMut(Self::Item) -> bool,
+    {
+        self.0.all(f)
+    }
+
+    #[inline]
+    fn any<F>(&mut self, f: F) -> bool
+    where
+        F: FnMut(Self::Item) -> bool,
+    {
+        self.0.any(f)
+    }
+
+    #[inline]
+    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
+    where
+        P: FnMut(&Self::Item) -> bool,
+    {
+        self.0.find(predicate)
+    }
+
+    #[inline]
+    fn position<P>(&mut self, predicate: P) -> Option<usize>
+    where
+        P: FnMut(Self::Item) -> bool,
+    {
+        self.0.position(predicate)
+    }
+
+    #[inline]
+    fn rposition<P>(&mut self, predicate: P) -> Option<usize>
+    where
+        P: FnMut(Self::Item) -> bool,
+    {
+        self.0.rposition(predicate)
+    }
+
+    #[inline]
+    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 {
+        // SAFETY: the caller must uphold the safety contract
+        // for `Iterator::__iterator_get_unchecked`.
+        unsafe { self.0.__iterator_get_unchecked(idx) }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl DoubleEndedIterator for Bytes<'_> {
+    #[inline]
+    fn next_back(&mut self) -> Option<u8> {
+        self.0.next_back()
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        self.0.nth_back(n)
+    }
+
+    #[inline]
+    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
+    where
+        P: FnMut(&Self::Item) -> bool,
+    {
+        self.0.rfind(predicate)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExactSizeIterator for Bytes<'_> {
+    #[inline]
+    fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for Bytes<'_> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl TrustedLen for Bytes<'_> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl TrustedRandomAccess for Bytes<'_> {
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
+/// This macro generates a Clone impl for string pattern API
+/// wrapper types of the form X<'a, P>
+macro_rules! derive_pattern_clone {
+    (clone $t:ident with |$s:ident| $e:expr) => {
+        impl<'a, P> Clone for $t<'a, P>
+        where
+            P: Pattern<'a, Searcher: Clone>,
+        {
+            fn clone(&self) -> Self {
+                let $s = self;
+                $e
+            }
+        }
+    };
+}
+
+/// This macro generates two public iterator structs
+/// wrapping a private internal one that makes use of the `Pattern` API.
+///
+/// For all patterns `P: Pattern<'a>` the following items will be
+/// generated (generics omitted):
+///
+/// struct $forward_iterator($internal_iterator);
+/// struct $reverse_iterator($internal_iterator);
+///
+/// impl Iterator for $forward_iterator
+/// { /* internal ends up calling Searcher::next_match() */ }
+///
+/// impl DoubleEndedIterator for $forward_iterator
+///       where P::Searcher: DoubleEndedSearcher
+/// { /* internal ends up calling Searcher::next_match_back() */ }
+///
+/// impl Iterator for $reverse_iterator
+///       where P::Searcher: ReverseSearcher
+/// { /* internal ends up calling Searcher::next_match_back() */ }
+///
+/// impl DoubleEndedIterator for $reverse_iterator
+///       where P::Searcher: DoubleEndedSearcher
+/// { /* internal ends up calling Searcher::next_match() */ }
+///
+/// The internal one is defined outside the macro, and has almost the same
+/// semantic as a DoubleEndedIterator by delegating to `pattern::Searcher` and
+/// `pattern::ReverseSearcher` for both forward and reverse iteration.
+///
+/// "Almost", because a `Searcher` and a `ReverseSearcher` for a given
+/// `Pattern` might not return the same elements, so actually implementing
+/// `DoubleEndedIterator` for it would be incorrect.
+/// (See the docs in `str::pattern` for more details)
+///
+/// However, the internal struct still represents a single ended iterator from
+/// either end, and depending on pattern is also a valid double ended iterator,
+/// so the two wrapper structs implement `Iterator`
+/// and `DoubleEndedIterator` depending on the concrete pattern type, leading
+/// to the complex impls seen above.
+macro_rules! generate_pattern_iterators {
+    {
+        // Forward iterator
+        forward:
+            $(#[$forward_iterator_attribute:meta])*
+            struct $forward_iterator:ident;
+
+        // Reverse iterator
+        reverse:
+            $(#[$reverse_iterator_attribute:meta])*
+            struct $reverse_iterator:ident;
+
+        // Stability of all generated items
+        stability:
+            $(#[$common_stability_attribute:meta])*
+
+        // Internal almost-iterator that is being delegated to
+        internal:
+            $internal_iterator:ident yielding ($iterty:ty);
+
+        // Kind of delegation - either single ended or double ended
+        delegate $($t:tt)*
+    } => {
+        $(#[$forward_iterator_attribute])*
+        $(#[$common_stability_attribute])*
+        pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>);
+
+        $(#[$common_stability_attribute])*
+        impl<'a, P> fmt::Debug for $forward_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: fmt::Debug>,
+        {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                f.debug_tuple(stringify!($forward_iterator))
+                    .field(&self.0)
+                    .finish()
+            }
+        }
+
+        $(#[$common_stability_attribute])*
+        impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> {
+            type Item = $iterty;
+
+            #[inline]
+            fn next(&mut self) -> Option<$iterty> {
+                self.0.next()
+            }
+        }
+
+        $(#[$common_stability_attribute])*
+        impl<'a, P> Clone for $forward_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: Clone>,
+        {
+            fn clone(&self) -> Self {
+                $forward_iterator(self.0.clone())
+            }
+        }
+
+        $(#[$reverse_iterator_attribute])*
+        $(#[$common_stability_attribute])*
+        pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>);
+
+        $(#[$common_stability_attribute])*
+        impl<'a, P> fmt::Debug for $reverse_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: fmt::Debug>,
+        {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                f.debug_tuple(stringify!($reverse_iterator))
+                    .field(&self.0)
+                    .finish()
+            }
+        }
+
+        $(#[$common_stability_attribute])*
+        impl<'a, P> Iterator for $reverse_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        {
+            type Item = $iterty;
+
+            #[inline]
+            fn next(&mut self) -> Option<$iterty> {
+                self.0.next_back()
+            }
+        }
+
+        $(#[$common_stability_attribute])*
+        impl<'a, P> Clone for $reverse_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: Clone>,
+        {
+            fn clone(&self) -> Self {
+                $reverse_iterator(self.0.clone())
+            }
+        }
+
+        #[stable(feature = "fused", since = "1.26.0")]
+        impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {}
+
+        #[stable(feature = "fused", since = "1.26.0")]
+        impl<'a, P> FusedIterator for $reverse_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
+        {}
+
+        generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*,
+                                                $forward_iterator,
+                                                $reverse_iterator, $iterty);
+    };
+    {
+        double ended; with $(#[$common_stability_attribute:meta])*,
+                           $forward_iterator:ident,
+                           $reverse_iterator:ident, $iterty:ty
+    } => {
+        $(#[$common_stability_attribute])*
+        impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
+        {
+            #[inline]
+            fn next_back(&mut self) -> Option<$iterty> {
+                self.0.next_back()
+            }
+        }
+
+        $(#[$common_stability_attribute])*
+        impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P>
+        where
+            P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
+        {
+            #[inline]
+            fn next_back(&mut self) -> Option<$iterty> {
+                self.0.next()
+            }
+        }
+    };
+    {
+        single ended; with $(#[$common_stability_attribute:meta])*,
+                           $forward_iterator:ident,
+                           $reverse_iterator:ident, $iterty:ty
+    } => {}
+}
+
+derive_pattern_clone! {
+    clone SplitInternal
+    with |s| SplitInternal { matcher: s.matcher.clone(), ..*s }
+}
+
+pub(super) struct SplitInternal<'a, P: Pattern<'a>> {
+    pub(super) start: usize,
+    pub(super) end: usize,
+    pub(super) matcher: P::Searcher,
+    pub(super) allow_trailing_empty: bool,
+    pub(super) finished: bool,
+}
+
+impl<'a, P> fmt::Debug for SplitInternal<'a, P>
+where
+    P: Pattern<'a, Searcher: fmt::Debug>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitInternal")
+            .field("start", &self.start)
+            .field("end", &self.end)
+            .field("matcher", &self.matcher)
+            .field("allow_trailing_empty", &self.allow_trailing_empty)
+            .field("finished", &self.finished)
+            .finish()
+    }
+}
+
+impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
+    #[inline]
+    fn get_end(&mut self) -> Option<&'a str> {
+        if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
+            self.finished = true;
+            // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+            unsafe {
+                let string = self.matcher.haystack().get_unchecked(self.start..self.end);
+                Some(string)
+            }
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        if self.finished {
+            return None;
+        }
+
+        let haystack = self.matcher.haystack();
+        match self.matcher.next_match() {
+            // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries.
+            Some((a, b)) => unsafe {
+                let elt = haystack.get_unchecked(self.start..a);
+                self.start = b;
+                Some(elt)
+            },
+            None => self.get_end(),
+        }
+    }
+
+    #[inline]
+    fn next_inclusive(&mut self) -> Option<&'a str> {
+        if self.finished {
+            return None;
+        }
+
+        let haystack = self.matcher.haystack();
+        match self.matcher.next_match() {
+            // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
+            // and self.start is either the start of the original string,
+            // or `b` was assigned to it, so it also lies on unicode boundary.
+            Some((_, b)) => unsafe {
+                let elt = haystack.get_unchecked(self.start..b);
+                self.start = b;
+                Some(elt)
+            },
+            None => self.get_end(),
+        }
+    }
+
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str>
+    where
+        P::Searcher: ReverseSearcher<'a>,
+    {
+        if self.finished {
+            return None;
+        }
+
+        if !self.allow_trailing_empty {
+            self.allow_trailing_empty = true;
+            match self.next_back() {
+                Some(elt) if !elt.is_empty() => return Some(elt),
+                _ => {
+                    if self.finished {
+                        return None;
+                    }
+                }
+            }
+        }
+
+        let haystack = self.matcher.haystack();
+        match self.matcher.next_match_back() {
+            // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries.
+            Some((a, b)) => unsafe {
+                let elt = haystack.get_unchecked(b..self.end);
+                self.end = a;
+                Some(elt)
+            },
+            // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+            None => unsafe {
+                self.finished = true;
+                Some(haystack.get_unchecked(self.start..self.end))
+            },
+        }
+    }
+
+    #[inline]
+    fn next_back_inclusive(&mut self) -> Option<&'a str>
+    where
+        P::Searcher: ReverseSearcher<'a>,
+    {
+        if self.finished {
+            return None;
+        }
+
+        if !self.allow_trailing_empty {
+            self.allow_trailing_empty = true;
+            match self.next_back_inclusive() {
+                Some(elt) if !elt.is_empty() => return Some(elt),
+                _ => {
+                    if self.finished {
+                        return None;
+                    }
+                }
+            }
+        }
+
+        let haystack = self.matcher.haystack();
+        match self.matcher.next_match_back() {
+            // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
+            // and self.end is either the end of the original string,
+            // or `b` was assigned to it, so it also lies on unicode boundary.
+            Some((_, b)) => unsafe {
+                let elt = haystack.get_unchecked(b..self.end);
+                self.end = b;
+                Some(elt)
+            },
+            // SAFETY: self.start is either the start of the original string,
+            // or start of a substring that represents the part of the string that hasn't
+            // iterated yet. Either way, it is guaranteed to lie on unicode boundary.
+            // self.end is either the end of the original string,
+            // or `b` was assigned to it, so it also lies on unicode boundary.
+            None => unsafe {
+                self.finished = true;
+                Some(haystack.get_unchecked(self.start..self.end))
+            },
+        }
+    }
+
+    #[inline]
+    fn as_str(&self) -> &'a str {
+        // `Self::get_end` doesn't change `self.start`
+        if self.finished {
+            return "";
+        }
+
+        // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+        unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
+    }
+}
+
+generate_pattern_iterators! {
+    forward:
+        /// Created with the method [`split`].
+        ///
+        /// [`split`]: str::split
+        struct Split;
+    reverse:
+        /// Created with the method [`rsplit`].
+        ///
+        /// [`rsplit`]: str::rsplit
+        struct RSplit;
+    stability:
+        #[stable(feature = "rust1", since = "1.0.0")]
+    internal:
+        SplitInternal yielding (&'a str);
+    delegate double ended;
+}
+
+impl<'a, P: Pattern<'a>> Split<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".split(' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+impl<'a, P: Pattern<'a>> RSplit<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".rsplit(' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+generate_pattern_iterators! {
+    forward:
+        /// Created with the method [`split_terminator`].
+        ///
+        /// [`split_terminator`]: str::split_terminator
+        struct SplitTerminator;
+    reverse:
+        /// Created with the method [`rsplit_terminator`].
+        ///
+        /// [`rsplit_terminator`]: str::rsplit_terminator
+        struct RSplitTerminator;
+    stability:
+        #[stable(feature = "rust1", since = "1.0.0")]
+    internal:
+        SplitInternal yielding (&'a str);
+    delegate double ended;
+}
+
+impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "A..B..".split_terminator('.');
+    /// assert_eq!(split.as_str(), "A..B..");
+    /// split.next();
+    /// assert_eq!(split.as_str(), ".B..");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "A..B..".rsplit_terminator('.');
+    /// assert_eq!(split.as_str(), "A..B..");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "A..B");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+derive_pattern_clone! {
+    clone SplitNInternal
+    with |s| SplitNInternal { iter: s.iter.clone(), ..*s }
+}
+
+pub(super) struct SplitNInternal<'a, P: Pattern<'a>> {
+    pub(super) iter: SplitInternal<'a, P>,
+    /// The number of splits remaining
+    pub(super) count: usize,
+}
+
+impl<'a, P> fmt::Debug for SplitNInternal<'a, P>
+where
+    P: Pattern<'a, Searcher: fmt::Debug>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitNInternal")
+            .field("iter", &self.iter)
+            .field("count", &self.count)
+            .finish()
+    }
+}
+
+impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        match self.count {
+            0 => None,
+            1 => {
+                self.count = 0;
+                self.iter.get_end()
+            }
+            _ => {
+                self.count -= 1;
+                self.iter.next()
+            }
+        }
+    }
+
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str>
+    where
+        P::Searcher: ReverseSearcher<'a>,
+    {
+        match self.count {
+            0 => None,
+            1 => {
+                self.count = 0;
+                self.iter.get_end()
+            }
+            _ => {
+                self.count -= 1;
+                self.iter.next_back()
+            }
+        }
+    }
+
+    #[inline]
+    fn as_str(&self) -> &'a str {
+        self.iter.as_str()
+    }
+}
+
+generate_pattern_iterators! {
+    forward:
+        /// Created with the method [`splitn`].
+        ///
+        /// [`splitn`]: str::splitn
+        struct SplitN;
+    reverse:
+        /// Created with the method [`rsplitn`].
+        ///
+        /// [`rsplitn`]: str::rsplitn
+        struct RSplitN;
+    stability:
+        #[stable(feature = "rust1", since = "1.0.0")]
+    internal:
+        SplitNInternal yielding (&'a str);
+    delegate single ended;
+}
+
+impl<'a, P: Pattern<'a>> SplitN<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".splitn(3, ' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+derive_pattern_clone! {
+    clone MatchIndicesInternal
+    with |s| MatchIndicesInternal(s.0.clone())
+}
+
+pub(super) struct MatchIndicesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher);
+
+impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P>
+where
+    P: Pattern<'a, Searcher: fmt::Debug>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("MatchIndicesInternal").field(&self.0).finish()
+    }
+}
+
+impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
+    #[inline]
+    fn next(&mut self) -> Option<(usize, &'a str)> {
+        self.0
+            .next_match()
+            // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
+            .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) })
+    }
+
+    #[inline]
+    fn next_back(&mut self) -> Option<(usize, &'a str)>
+    where
+        P::Searcher: ReverseSearcher<'a>,
+    {
+        self.0
+            .next_match_back()
+            // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
+            .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) })
+    }
+}
+
+generate_pattern_iterators! {
+    forward:
+        /// Created with the method [`match_indices`].
+        ///
+        /// [`match_indices`]: str::match_indices
+        struct MatchIndices;
+    reverse:
+        /// Created with the method [`rmatch_indices`].
+        ///
+        /// [`rmatch_indices`]: str::rmatch_indices
+        struct RMatchIndices;
+    stability:
+        #[stable(feature = "str_match_indices", since = "1.5.0")]
+    internal:
+        MatchIndicesInternal yielding ((usize, &'a str));
+    delegate double ended;
+}
+
+derive_pattern_clone! {
+    clone MatchesInternal
+    with |s| MatchesInternal(s.0.clone())
+}
+
+pub(super) struct MatchesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher);
+
+impl<'a, P> fmt::Debug for MatchesInternal<'a, P>
+where
+    P: Pattern<'a, Searcher: fmt::Debug>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("MatchesInternal").field(&self.0).finish()
+    }
+}
+
+impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> {
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
+        self.0.next_match().map(|(a, b)| unsafe {
+            // Indices are known to be on utf8 boundaries
+            self.0.haystack().get_unchecked(a..b)
+        })
+    }
+
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str>
+    where
+        P::Searcher: ReverseSearcher<'a>,
+    {
+        // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
+        self.0.next_match_back().map(|(a, b)| unsafe {
+            // Indices are known to be on utf8 boundaries
+            self.0.haystack().get_unchecked(a..b)
+        })
+    }
+}
+
+generate_pattern_iterators! {
+    forward:
+        /// Created with the method [`matches`].
+        ///
+        /// [`matches`]: str::matches
+        struct Matches;
+    reverse:
+        /// Created with the method [`rmatches`].
+        ///
+        /// [`rmatches`]: str::rmatches
+        struct RMatches;
+    stability:
+        #[stable(feature = "str_matches", since = "1.2.0")]
+    internal:
+        MatchesInternal yielding (&'a str);
+    delegate double ended;
+}
+
+/// An iterator over the lines of a string, as string slices.
+///
+/// This struct is created with the [`lines`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`lines`]: str::lines
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone, Debug)]
+pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for Lines<'a> {
+    type Item = &'a str;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        self.0.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a str> {
+        self.next_back()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> DoubleEndedIterator for Lines<'a> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str> {
+        self.0.next_back()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for Lines<'_> {}
+
+/// Created with the method [`lines_any`].
+///
+/// [`lines_any`]: str::lines_any
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
+#[derive(Clone, Debug)]
+#[allow(deprecated)]
+pub struct LinesAny<'a>(pub(super) Lines<'a>);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+impl<'a> Iterator for LinesAny<'a> {
+    type Item = &'a str;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        self.0.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+impl<'a> DoubleEndedIterator for LinesAny<'a> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str> {
+        self.0.next_back()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+#[allow(deprecated)]
+impl FusedIterator for LinesAny<'_> {}
+
+/// An iterator over the non-whitespace substrings of a string,
+/// separated by any amount of whitespace.
+///
+/// This struct is created by the [`split_whitespace`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`split_whitespace`]: str::split_whitespace
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+#[derive(Clone, Debug)]
+pub struct SplitWhitespace<'a> {
+    pub(super) inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>,
+}
+
+/// An iterator over the non-ASCII-whitespace substrings of a string,
+/// separated by any amount of ASCII whitespace.
+///
+/// This struct is created by the [`split_ascii_whitespace`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`split_ascii_whitespace`]: str::split_ascii_whitespace
+#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
+#[derive(Clone, Debug)]
+pub struct SplitAsciiWhitespace<'a> {
+    pub(super) inner:
+        Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty>, UnsafeBytesToStr>,
+}
+
+/// An iterator over the substrings of a string,
+/// terminated by a substring matching to a predicate function
+/// Unlike `Split`, it contains the matched part as a terminator
+/// of the subslice.
+///
+/// This struct is created by the [`split_inclusive`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`split_inclusive`]: str::split_inclusive
+#[unstable(feature = "split_inclusive", issue = "72360")]
+pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>);
+
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+impl<'a> Iterator for SplitWhitespace<'a> {
+    type Item = &'a str;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        self.inner.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a str> {
+        self.next_back()
+    }
+}
+
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str> {
+        self.inner.next_back()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for SplitWhitespace<'_> {}
+
+#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
+impl<'a> Iterator for SplitAsciiWhitespace<'a> {
+    type Item = &'a str;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        self.inner.next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a str> {
+        self.next_back()
+    }
+}
+
+#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
+impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str> {
+        self.inner.next_back()
+    }
+}
+
+#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
+impl FusedIterator for SplitAsciiWhitespace<'_> {}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
+    type Item = &'a str;
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a str> {
+        self.0.next_inclusive()
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SplitInclusive").field("0", &self.0).finish()
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> {
+    fn clone(&self) -> Self {
+        SplitInclusive(self.0.clone())
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
+    for SplitInclusive<'a, P>
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a str> {
+        self.0.next_back_inclusive()
+    }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
+
+impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_inclusive_as_str)]
+    /// #![feature(split_inclusive)]
+    /// let mut split = "Mary had a little lamb".split_inclusive(' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+/// An iterator of [`u16`] over the string encoded as UTF-16.
+///
+/// This struct is created by the [`encode_utf16`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`encode_utf16`]: str::encode_utf16
+#[derive(Clone)]
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+pub struct EncodeUtf16<'a> {
+    pub(super) chars: Chars<'a>,
+    pub(super) extra: u16,
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl fmt::Debug for EncodeUtf16<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad("EncodeUtf16 { .. }")
+    }
+}
+
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+impl<'a> Iterator for EncodeUtf16<'a> {
+    type Item = u16;
+
+    #[inline]
+    fn next(&mut self) -> Option<u16> {
+        if self.extra != 0 {
+            let tmp = self.extra;
+            self.extra = 0;
+            return Some(tmp);
+        }
+
+        let mut buf = [0; 2];
+        self.chars.next().map(|ch| {
+            let n = ch.encode_utf16(&mut buf).len();
+            if n == 2 {
+                self.extra = buf[1];
+            }
+            buf[0]
+        })
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let (low, high) = self.chars.size_hint();
+        // every char gets either one u16 or two u16,
+        // so this iterator is between 1 or 2 times as
+        // long as the underlying iterator.
+        (low, high.and_then(|n| n.checked_mul(2)))
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl FusedIterator for EncodeUtf16<'_> {}
+
+/// The return type of [`str::escape_debug`].
+#[stable(feature = "str_escape", since = "1.34.0")]
+#[derive(Clone, Debug)]
+pub struct EscapeDebug<'a> {
+    pub(super) inner: Chain<
+        Flatten<option::IntoIter<char::EscapeDebug>>,
+        FlatMap<Chars<'a>, char::EscapeDebug, CharEscapeDebugContinue>,
+    >,
+}
+
+/// The return type of [`str::escape_default`].
+#[stable(feature = "str_escape", since = "1.34.0")]
+#[derive(Clone, Debug)]
+pub struct EscapeDefault<'a> {
+    pub(super) inner: FlatMap<Chars<'a>, char::EscapeDefault, CharEscapeDefault>,
+}
+
+/// The return type of [`str::escape_unicode`].
+#[stable(feature = "str_escape", since = "1.34.0")]
+#[derive(Clone, Debug)]
+pub struct EscapeUnicode<'a> {
+    pub(super) inner: FlatMap<Chars<'a>, char::EscapeUnicode, CharEscapeUnicode>,
+}
+
+macro_rules! escape_types_impls {
+    ($( $Name: ident ),+) => {$(
+        #[stable(feature = "str_escape", since = "1.34.0")]
+        impl<'a> fmt::Display for $Name<'a> {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                self.clone().try_for_each(|c| f.write_char(c))
+            }
+        }
+
+        #[stable(feature = "str_escape", since = "1.34.0")]
+        impl<'a> Iterator for $Name<'a> {
+            type Item = char;
+
+            #[inline]
+            fn next(&mut self) -> Option<char> { self.inner.next() }
+
+            #[inline]
+            fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+
+            #[inline]
+            fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
+                Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+            {
+                self.inner.try_fold(init, fold)
+            }
+
+            #[inline]
+            fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+                where Fold: FnMut(Acc, Self::Item) -> Acc,
+            {
+                self.inner.fold(init, fold)
+            }
+        }
+
+        #[stable(feature = "str_escape", since = "1.34.0")]
+        impl<'a> FusedIterator for $Name<'a> {}
+    )+}
+}
+
+escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode);
diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs
index 88b2bc5..720a35b 100644
--- a/library/core/src/str/lossy.rs
+++ b/library/core/src/str/lossy.rs
@@ -1,7 +1,9 @@
 use crate::char;
 use crate::fmt::{self, Write};
 use crate::mem;
-use crate::str as core_str;
+
+use super::from_utf8_unchecked;
+use super::validations::utf8_char_width;
 
 /// Lossy UTF-8 string.
 #[unstable(feature = "str_internals", issue = "none")]
@@ -66,14 +68,14 @@
 
             if byte < 128 {
             } else {
-                let w = core_str::utf8_char_width(byte);
+                let w = utf8_char_width(byte);
 
                 macro_rules! error {
                     () => {{
                         // SAFETY: We have checked up to `i` that source is valid UTF-8.
                         unsafe {
                             let r = Utf8LossyChunk {
-                                valid: core_str::from_utf8_unchecked(&self.source[0..i_]),
+                                valid: from_utf8_unchecked(&self.source[0..i_]),
                                 broken: &self.source[i_..i],
                             };
                             self.source = &self.source[i..];
@@ -133,7 +135,7 @@
 
         let r = Utf8LossyChunk {
             // SAFETY: We have checked that the entire source is valid UTF-8.
-            valid: unsafe { core_str::from_utf8_unchecked(self.source) },
+            valid: unsafe { from_utf8_unchecked(self.source) },
             broken: &[],
         };
         self.source = &[];
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index e4a6b7e..3e18a4e 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 //! String manipulation.
 //!
 //! For more details, see the [`std::str`] module.
@@ -8,18 +6,18 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+mod converts;
+mod error;
+mod iter;
+mod traits;
+mod validations;
+
 use self::pattern::Pattern;
 use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
 
 use crate::char;
-use crate::fmt::{self, Write};
-use crate::iter::TrustedRandomAccess;
-use crate::iter::{Chain, FlatMap, Flatten};
-use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen};
 use crate::mem;
-use crate::ops::Try;
-use crate::option;
-use crate::slice::{self, SliceIndex, Split as SliceSplit};
+use crate::slice::{self, SliceIndex};
 
 pub mod pattern;
 
@@ -27,2191 +25,57 @@
 #[allow(missing_docs)]
 pub mod lossy;
 
-/// Parse a value from a string
-///
-/// `FromStr`'s [`from_str`] method is often used implicitly, through
-/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples.
-///
-/// [`from_str`]: FromStr::from_str
-/// [`parse`]: str::parse
-///
-/// `FromStr` does not have a lifetime parameter, and so you can only parse types
-/// that do not contain a lifetime parameter themselves. In other words, you can
-/// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that
-/// contains an `i32`, but not one that contains an `&i32`.
-///
-/// # Examples
-///
-/// Basic implementation of `FromStr` on an example `Point` type:
-///
-/// ```
-/// use std::str::FromStr;
-/// use std::num::ParseIntError;
-///
-/// #[derive(Debug, PartialEq)]
-/// struct Point {
-///     x: i32,
-///     y: i32
-/// }
-///
-/// impl FromStr for Point {
-///     type Err = ParseIntError;
-///
-///     fn from_str(s: &str) -> Result<Self, Self::Err> {
-///         let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
-///                                  .split(',')
-///                                  .collect();
-///
-///         let x_fromstr = coords[0].parse::<i32>()?;
-///         let y_fromstr = coords[1].parse::<i32>()?;
-///
-///         Ok(Point { x: x_fromstr, y: y_fromstr })
-///     }
-/// }
-///
-/// let p = Point::from_str("(1,2)");
-/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} )
-/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait FromStr: Sized {
-    /// The associated error which can be returned from parsing.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    type Err;
+pub use converts::{from_utf8, from_utf8_unchecked};
 
-    /// Parses a string `s` to return a value of this type.
-    ///
-    /// If parsing succeeds, return the value inside [`Ok`], otherwise
-    /// when the string is ill-formatted return an error specific to the
-    /// inside [`Err`]. The error type is specific to implementation of the trait.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`:
-    ///
-    /// [ithirtytwo]: ../../std/primitive.i32.html
-    ///
-    /// ```
-    /// use std::str::FromStr;
-    ///
-    /// let s = "5";
-    /// let x = i32::from_str(s).unwrap();
-    ///
-    /// assert_eq!(5, x);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn from_str(s: &str) -> Result<Self, Self::Err>;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl FromStr for bool {
-    type Err = ParseBoolError;
-
-    /// Parse a `bool` from a string.
-    ///
-    /// Yields a `Result<bool, ParseBoolError>`, because `s` may or may not
-    /// actually be parseable.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::str::FromStr;
-    ///
-    /// assert_eq!(FromStr::from_str("true"), Ok(true));
-    /// assert_eq!(FromStr::from_str("false"), Ok(false));
-    /// assert!(<bool as FromStr>::from_str("not even a boolean").is_err());
-    /// ```
-    ///
-    /// Note, in many cases, the `.parse()` method on `str` is more proper.
-    ///
-    /// ```
-    /// assert_eq!("true".parse(), Ok(true));
-    /// assert_eq!("false".parse(), Ok(false));
-    /// assert!("not even a boolean".parse::<bool>().is_err());
-    /// ```
-    #[inline]
-    fn from_str(s: &str) -> Result<bool, ParseBoolError> {
-        match s {
-            "true" => Ok(true),
-            "false" => Ok(false),
-            _ => Err(ParseBoolError { _priv: () }),
-        }
-    }
-}
-
-/// An error returned when parsing a `bool` using [`from_str`] fails
-///
-/// [`from_str`]: FromStr::from_str
-#[derive(Debug, Clone, PartialEq, Eq)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ParseBoolError {
-    _priv: (),
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for ParseBoolError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        "provided string was not `true` or `false`".fmt(f)
-    }
-}
-
-/*
-Section: Creating a string
-*/
-
-/// Errors which can occur when attempting to interpret a sequence of [`u8`]
-/// as a string.
-///
-/// As such, the `from_utf8` family of functions and methods for both [`String`]s
-/// and [`&str`]s make use of this error, for example.
-///
-/// [`String`]: ../../std/string/struct.String.html#method.from_utf8
-/// [`&str`]: from_utf8
-///
-/// # Examples
-///
-/// This error type’s methods can be used to create functionality
-/// similar to `String::from_utf8_lossy` without allocating heap memory:
-///
-/// ```
-/// fn from_utf8_lossy<F>(mut input: &[u8], mut push: F) where F: FnMut(&str) {
-///     loop {
-///         match std::str::from_utf8(input) {
-///             Ok(valid) => {
-///                 push(valid);
-///                 break
-///             }
-///             Err(error) => {
-///                 let (valid, after_valid) = input.split_at(error.valid_up_to());
-///                 unsafe {
-///                     push(std::str::from_utf8_unchecked(valid))
-///                 }
-///                 push("\u{FFFD}");
-///
-///                 if let Some(invalid_sequence_length) = error.error_len() {
-///                     input = &after_valid[invalid_sequence_length..]
-///                 } else {
-///                     break
-///                 }
-///             }
-///         }
-///     }
-/// }
-/// ```
-#[derive(Copy, Eq, PartialEq, Clone, Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Utf8Error {
-    valid_up_to: usize,
-    error_len: Option<u8>,
-}
-
-impl Utf8Error {
-    /// Returns the index in the given string up to which valid UTF-8 was
-    /// verified.
-    ///
-    /// It is the maximum index such that `from_utf8(&input[..index])`
-    /// would return `Ok(_)`.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use std::str;
-    ///
-    /// // some invalid bytes, in a vector
-    /// let sparkle_heart = vec![0, 159, 146, 150];
-    ///
-    /// // std::str::from_utf8 returns a Utf8Error
-    /// let error = str::from_utf8(&sparkle_heart).unwrap_err();
-    ///
-    /// // the second byte is invalid here
-    /// assert_eq!(1, error.valid_up_to());
-    /// ```
-    #[stable(feature = "utf8_error", since = "1.5.0")]
-    pub fn valid_up_to(&self) -> usize {
-        self.valid_up_to
-    }
-
-    /// Provides more information about the failure:
-    ///
-    /// * `None`: the end of the input was reached unexpectedly.
-    ///   `self.valid_up_to()` is 1 to 3 bytes from the end of the input.
-    ///   If a byte stream (such as a file or a network socket) is being decoded incrementally,
-    ///   this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks.
-    ///
-    /// * `Some(len)`: an unexpected byte was encountered.
-    ///   The length provided is that of the invalid byte sequence
-    ///   that starts at the index given by `valid_up_to()`.
-    ///   Decoding should resume after that sequence
-    ///   (after inserting a [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]) in case of
-    ///   lossy decoding.
-    ///
-    /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
-    #[stable(feature = "utf8_error_error_len", since = "1.20.0")]
-    pub fn error_len(&self) -> Option<usize> {
-        self.error_len.map(|len| len as usize)
-    }
-}
-
-/// Converts a slice of bytes to a string slice.
-///
-/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice
-/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between
-/// the two. Not all byte slices are valid string slices, however: [`&str`] requires
-/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid
-/// UTF-8, and then does the conversion.
-///
-/// [`&str`]: str
-/// [byteslice]: ../../std/primitive.slice.html
-///
-/// If you are sure that the byte slice is valid UTF-8, and you don't want to
-/// incur the overhead of the validity check, there is an unsafe version of
-/// this function, [`from_utf8_unchecked`], which has the same
-/// behavior but skips the check.
-///
-/// If you need a `String` instead of a `&str`, consider
-/// [`String::from_utf8`][string].
-///
-/// [string]: ../../std/string/struct.String.html#method.from_utf8
-///
-/// Because you can stack-allocate a `[u8; N]`, and you can take a
-/// [`&[u8]`][byteslice] of it, this function is one way to have a
-/// stack-allocated string. There is an example of this in the
-/// examples section below.
-///
-/// [byteslice]: ../../std/primitive.slice.html
-///
-/// # Errors
-///
-/// Returns `Err` if the slice is not UTF-8 with a description as to why the
-/// provided slice is not UTF-8.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::str;
-///
-/// // some bytes, in a vector
-/// let sparkle_heart = vec![240, 159, 146, 150];
-///
-/// // We know these bytes are valid, so just use `unwrap()`.
-/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap();
-///
-/// assert_eq!("💖", sparkle_heart);
-/// ```
-///
-/// Incorrect bytes:
-///
-/// ```
-/// use std::str;
-///
-/// // some invalid bytes, in a vector
-/// let sparkle_heart = vec![0, 159, 146, 150];
-///
-/// assert!(str::from_utf8(&sparkle_heart).is_err());
-/// ```
-///
-/// See the docs for [`Utf8Error`] for more details on the kinds of
-/// errors that can be returned.
-///
-/// A "stack allocated string":
-///
-/// ```
-/// use std::str;
-///
-/// // some bytes, in a stack-allocated array
-/// let sparkle_heart = [240, 159, 146, 150];
-///
-/// // We know these bytes are valid, so just use `unwrap()`.
-/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap();
-///
-/// assert_eq!("💖", sparkle_heart);
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
-    run_utf8_validation(v)?;
-    // SAFETY: Just ran validation.
-    Ok(unsafe { from_utf8_unchecked(v) })
-}
-
-/// Converts a mutable slice of bytes to a mutable string slice.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::str;
-///
-/// // "Hello, Rust!" as a mutable vector
-/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
-///
-/// // As we know these bytes are valid, we can use `unwrap()`
-/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap();
-///
-/// assert_eq!("Hello, Rust!", outstr);
-/// ```
-///
-/// Incorrect bytes:
-///
-/// ```
-/// use std::str;
-///
-/// // Some invalid bytes in a mutable vector
-/// let mut invalid = vec![128, 223];
-///
-/// assert!(str::from_utf8_mut(&mut invalid).is_err());
-/// ```
-/// See the docs for [`Utf8Error`] for more details on the kinds of
-/// errors that can be returned.
 #[stable(feature = "str_mut_extras", since = "1.20.0")]
-pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
-    run_utf8_validation(v)?;
-    // SAFETY: Just ran validation.
-    Ok(unsafe { from_utf8_unchecked_mut(v) })
-}
-
-/// Converts a slice of bytes to a string slice without checking
-/// that the string contains valid UTF-8.
-///
-/// See the safe version, [`from_utf8`], for more information.
-///
-/// # Safety
-///
-/// This function is unsafe because it does not check that the bytes passed to
-/// it are valid UTF-8. If this constraint is violated, undefined behavior
-/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8.
-///
-/// [`&str`]: str
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::str;
-///
-/// // some bytes, in a vector
-/// let sparkle_heart = vec![240, 159, 146, 150];
-///
-/// let sparkle_heart = unsafe {
-///     str::from_utf8_unchecked(&sparkle_heart)
-/// };
-///
-/// assert_eq!("💖", sparkle_heart);
-/// ```
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")]
-#[allow(unused_attributes)]
-#[allow_internal_unstable(const_fn_transmute)]
-pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
-    // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8.
-    // Also relies on `&str` and `&[u8]` having the same layout.
-    unsafe { mem::transmute(v) }
-}
-
-/// Converts a slice of bytes to a string slice without checking
-/// that the string contains valid UTF-8; mutable version.
-///
-/// See the immutable version, [`from_utf8_unchecked()`] for more information.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::str;
-///
-/// let mut heart = vec![240, 159, 146, 150];
-/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
-///
-/// assert_eq!("💖", heart);
-/// ```
-#[inline]
-#[stable(feature = "str_mut_extras", since = "1.20.0")]
-pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
-    // SAFETY: the caller must guarantee that the bytes `v`
-    // are valid UTF-8, thus the cast to `*mut str` is safe.
-    // Also, the pointer dereference is safe because that pointer
-    // comes from a reference which is guaranteed to be valid for writes.
-    unsafe { &mut *(v as *mut [u8] as *mut str) }
-}
+pub use converts::{from_utf8_mut, from_utf8_unchecked_mut};
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for Utf8Error {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let Some(error_len) = self.error_len {
-            write!(
-                f,
-                "invalid utf-8 sequence of {} bytes from index {}",
-                error_len, self.valid_up_to
-            )
-        } else {
-            write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to)
-        }
-    }
-}
+pub use error::{ParseBoolError, Utf8Error};
 
-/*
-Section: Iterators
-*/
-
-/// An iterator over the [`char`]s of a string slice.
-///
-///
-/// This struct is created by the [`chars`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`char`]: prim@char
-/// [`chars`]: str::chars
-#[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct Chars<'a> {
-    iter: slice::Iter<'a, u8>,
-}
+pub use traits::FromStr;
 
-/// Returns the initial codepoint accumulator for the first byte.
-/// The first byte is special, only want bottom 5 bits for width 2, 4 bits
-/// for width 3, and 3 bits for width 4.
-#[inline]
-fn utf8_first_byte(byte: u8, width: u32) -> u32 {
-    (byte & (0x7F >> width)) as u32
-}
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{Bytes, CharIndices, Chars, Lines, SplitWhitespace};
 
-/// Returns the value of `ch` updated with continuation byte `byte`.
-#[inline]
-fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 {
-    (ch << 6) | (byte & CONT_MASK) as u32
-}
+#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
+pub use iter::LinesAny;
 
-/// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the
-/// bits `10`).
-#[inline]
-fn utf8_is_cont_byte(byte: u8) -> bool {
-    (byte & !CONT_MASK) == TAG_CONT_U8
-}
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{RSplit, RSplitTerminator, Split, SplitTerminator};
 
-#[inline]
-fn unwrap_or_0(opt: Option<&u8>) -> u8 {
-    match opt {
-        Some(&byte) => byte,
-        None => 0,
-    }
-}
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{RSplitN, SplitN};
 
-/// Reads the next code point out of a byte iterator (assuming a
-/// UTF-8-like encoding).
+#[stable(feature = "str_matches", since = "1.2.0")]
+pub use iter::{Matches, RMatches};
+
+#[stable(feature = "str_match_indices", since = "1.5.0")]
+pub use iter::{MatchIndices, RMatchIndices};
+
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+pub use iter::EncodeUtf16;
+
+#[stable(feature = "str_escape", since = "1.34.0")]
+pub use iter::{EscapeDebug, EscapeDefault, EscapeUnicode};
+
+#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
+pub use iter::SplitAsciiWhitespace;
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+use iter::SplitInclusive;
+
 #[unstable(feature = "str_internals", issue = "none")]
-#[inline]
-pub fn next_code_point<'a, I: Iterator<Item = &'a u8>>(bytes: &mut I) -> Option<u32> {
-    // Decode UTF-8
-    let x = *bytes.next()?;
-    if x < 128 {
-        return Some(x as u32);
-    }
+pub use validations::next_code_point;
 
-    // Multibyte case follows
-    // Decode from a byte combination out of: [[[x y] z] w]
-    // NOTE: Performance is sensitive to the exact formulation here
-    let init = utf8_first_byte(x, 2);
-    let y = unwrap_or_0(bytes.next());
-    let mut ch = utf8_acc_cont_byte(init, y);
-    if x >= 0xE0 {
-        // [[x y z] w] case
-        // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
-        let z = unwrap_or_0(bytes.next());
-        let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
-        ch = init << 12 | y_z;
-        if x >= 0xF0 {
-            // [x y z w] case
-            // use only the lower 3 bits of `init`
-            let w = unwrap_or_0(bytes.next());
-            ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
-        }
-    }
+use iter::MatchIndicesInternal;
+use iter::SplitInternal;
+use iter::{MatchesInternal, SplitNInternal};
 
-    Some(ch)
-}
-
-/// Reads the last code point out of a byte iterator (assuming a
-/// UTF-8-like encoding).
-#[inline]
-fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option<u32>
-where
-    I: DoubleEndedIterator<Item = &'a u8>,
-{
-    // Decode UTF-8
-    let w = match *bytes.next_back()? {
-        next_byte if next_byte < 128 => return Some(next_byte as u32),
-        back_byte => back_byte,
-    };
-
-    // Multibyte case follows
-    // Decode from a byte combination out of: [x [y [z w]]]
-    let mut ch;
-    let z = unwrap_or_0(bytes.next_back());
-    ch = utf8_first_byte(z, 2);
-    if utf8_is_cont_byte(z) {
-        let y = unwrap_or_0(bytes.next_back());
-        ch = utf8_first_byte(y, 3);
-        if utf8_is_cont_byte(y) {
-            let x = unwrap_or_0(bytes.next_back());
-            ch = utf8_first_byte(x, 4);
-            ch = utf8_acc_cont_byte(ch, y);
-        }
-        ch = utf8_acc_cont_byte(ch, z);
-    }
-    ch = utf8_acc_cont_byte(ch, w);
-
-    Some(ch)
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Iterator for Chars<'a> {
-    type Item = char;
-
-    #[inline]
-    fn next(&mut self) -> Option<char> {
-        next_code_point(&mut self.iter).map(|ch| {
-            // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value.
-            unsafe { char::from_u32_unchecked(ch) }
-        })
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        // length in `char` is equal to the number of non-continuation bytes
-        let bytes_len = self.iter.len();
-        let mut cont_bytes = 0;
-        for &byte in self.iter {
-            cont_bytes += utf8_is_cont_byte(byte) as usize;
-        }
-        bytes_len - cont_bytes
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let len = self.iter.len();
-        // `(len + 3)` can't overflow, because we know that the `slice::Iter`
-        // belongs to a slice in memory which has a maximum length of
-        // `isize::MAX` (that's well below `usize::MAX`).
-        ((len + 3) / 4, Some(len))
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<char> {
-        // No need to go through the entire string.
-        self.next_back()
-    }
-}
-
-#[stable(feature = "chars_debug_impl", since = "1.38.0")]
-impl fmt::Debug for Chars<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "Chars(")?;
-        f.debug_list().entries(self.clone()).finish()?;
-        write!(f, ")")?;
-        Ok(())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> DoubleEndedIterator for Chars<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<char> {
-        next_code_point_reverse(&mut self.iter).map(|ch| {
-            // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value.
-            unsafe { char::from_u32_unchecked(ch) }
-        })
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl FusedIterator for Chars<'_> {}
-
-impl<'a> Chars<'a> {
-    /// Views the underlying data as a subslice of the original data.
-    ///
-    /// This has the same lifetime as the original slice, and so the
-    /// iterator can continue to be used while this exists.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut chars = "abc".chars();
-    ///
-    /// assert_eq!(chars.as_str(), "abc");
-    /// chars.next();
-    /// assert_eq!(chars.as_str(), "bc");
-    /// chars.next();
-    /// chars.next();
-    /// assert_eq!(chars.as_str(), "");
-    /// ```
-    #[stable(feature = "iter_to_slice", since = "1.4.0")]
-    #[inline]
-    pub fn as_str(&self) -> &'a str {
-        // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8.
-        unsafe { from_utf8_unchecked(self.iter.as_slice()) }
-    }
-}
-
-/// An iterator over the [`char`]s of a string slice, and their positions.
-///
-/// This struct is created by the [`char_indices`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`char`]: prim@char
-/// [`char_indices`]: str::char_indices
-#[derive(Clone, Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct CharIndices<'a> {
-    front_offset: usize,
-    iter: Chars<'a>,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Iterator for CharIndices<'a> {
-    type Item = (usize, char);
-
-    #[inline]
-    fn next(&mut self) -> Option<(usize, char)> {
-        let pre_len = self.iter.iter.len();
-        match self.iter.next() {
-            None => None,
-            Some(ch) => {
-                let index = self.front_offset;
-                let len = self.iter.iter.len();
-                self.front_offset += pre_len - len;
-                Some((index, ch))
-            }
-        }
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.iter.count()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<(usize, char)> {
-        // No need to go through the entire string.
-        self.next_back()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> DoubleEndedIterator for CharIndices<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<(usize, char)> {
-        self.iter.next_back().map(|ch| {
-            let index = self.front_offset + self.iter.iter.len();
-            (index, ch)
-        })
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl FusedIterator for CharIndices<'_> {}
-
-impl<'a> CharIndices<'a> {
-    /// Views the underlying data as a subslice of the original data.
-    ///
-    /// This has the same lifetime as the original slice, and so the
-    /// iterator can continue to be used while this exists.
-    #[stable(feature = "iter_to_slice", since = "1.4.0")]
-    #[inline]
-    pub fn as_str(&self) -> &'a str {
-        self.iter.as_str()
-    }
-}
-
-/// An iterator over the bytes of a string slice.
-///
-/// This struct is created by the [`bytes`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`bytes`]: str::bytes
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone, Debug)]
-pub struct Bytes<'a>(Copied<slice::Iter<'a, u8>>);
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Iterator for Bytes<'_> {
-    type Item = u8;
-
-    #[inline]
-    fn next(&mut self) -> Option<u8> {
-        self.0.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.0.size_hint()
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.0.count()
-    }
-
-    #[inline]
-    fn last(self) -> Option<Self::Item> {
-        self.0.last()
-    }
-
-    #[inline]
-    fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        self.0.nth(n)
-    }
-
-    #[inline]
-    fn all<F>(&mut self, f: F) -> bool
-    where
-        F: FnMut(Self::Item) -> bool,
-    {
-        self.0.all(f)
-    }
-
-    #[inline]
-    fn any<F>(&mut self, f: F) -> bool
-    where
-        F: FnMut(Self::Item) -> bool,
-    {
-        self.0.any(f)
-    }
-
-    #[inline]
-    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
-    where
-        P: FnMut(&Self::Item) -> bool,
-    {
-        self.0.find(predicate)
-    }
-
-    #[inline]
-    fn position<P>(&mut self, predicate: P) -> Option<usize>
-    where
-        P: FnMut(Self::Item) -> bool,
-    {
-        self.0.position(predicate)
-    }
-
-    #[inline]
-    fn rposition<P>(&mut self, predicate: P) -> Option<usize>
-    where
-        P: FnMut(Self::Item) -> bool,
-    {
-        self.0.rposition(predicate)
-    }
-
-    #[inline]
-    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 {
-        // SAFETY: the caller must uphold the safety contract
-        // for `Iterator::__iterator_get_unchecked`.
-        unsafe { self.0.__iterator_get_unchecked(idx) }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl DoubleEndedIterator for Bytes<'_> {
-    #[inline]
-    fn next_back(&mut self) -> Option<u8> {
-        self.0.next_back()
-    }
-
-    #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
-        self.0.nth_back(n)
-    }
-
-    #[inline]
-    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
-    where
-        P: FnMut(&Self::Item) -> bool,
-    {
-        self.0.rfind(predicate)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl ExactSizeIterator for Bytes<'_> {
-    #[inline]
-    fn len(&self) -> usize {
-        self.0.len()
-    }
-
-    #[inline]
-    fn is_empty(&self) -> bool {
-        self.0.is_empty()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl FusedIterator for Bytes<'_> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl TrustedLen for Bytes<'_> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl TrustedRandomAccess for Bytes<'_> {
-    fn may_have_side_effect() -> bool {
-        false
-    }
-}
-
-/// This macro generates a Clone impl for string pattern API
-/// wrapper types of the form X<'a, P>
-macro_rules! derive_pattern_clone {
-    (clone $t:ident with |$s:ident| $e:expr) => {
-        impl<'a, P> Clone for $t<'a, P>
-        where
-            P: Pattern<'a, Searcher: Clone>,
-        {
-            fn clone(&self) -> Self {
-                let $s = self;
-                $e
-            }
-        }
-    };
-}
-
-/// This macro generates two public iterator structs
-/// wrapping a private internal one that makes use of the `Pattern` API.
-///
-/// For all patterns `P: Pattern<'a>` the following items will be
-/// generated (generics omitted):
-///
-/// struct $forward_iterator($internal_iterator);
-/// struct $reverse_iterator($internal_iterator);
-///
-/// impl Iterator for $forward_iterator
-/// { /* internal ends up calling Searcher::next_match() */ }
-///
-/// impl DoubleEndedIterator for $forward_iterator
-///       where P::Searcher: DoubleEndedSearcher
-/// { /* internal ends up calling Searcher::next_match_back() */ }
-///
-/// impl Iterator for $reverse_iterator
-///       where P::Searcher: ReverseSearcher
-/// { /* internal ends up calling Searcher::next_match_back() */ }
-///
-/// impl DoubleEndedIterator for $reverse_iterator
-///       where P::Searcher: DoubleEndedSearcher
-/// { /* internal ends up calling Searcher::next_match() */ }
-///
-/// The internal one is defined outside the macro, and has almost the same
-/// semantic as a DoubleEndedIterator by delegating to `pattern::Searcher` and
-/// `pattern::ReverseSearcher` for both forward and reverse iteration.
-///
-/// "Almost", because a `Searcher` and a `ReverseSearcher` for a given
-/// `Pattern` might not return the same elements, so actually implementing
-/// `DoubleEndedIterator` for it would be incorrect.
-/// (See the docs in `str::pattern` for more details)
-///
-/// However, the internal struct still represents a single ended iterator from
-/// either end, and depending on pattern is also a valid double ended iterator,
-/// so the two wrapper structs implement `Iterator`
-/// and `DoubleEndedIterator` depending on the concrete pattern type, leading
-/// to the complex impls seen above.
-macro_rules! generate_pattern_iterators {
-    {
-        // Forward iterator
-        forward:
-            $(#[$forward_iterator_attribute:meta])*
-            struct $forward_iterator:ident;
-
-        // Reverse iterator
-        reverse:
-            $(#[$reverse_iterator_attribute:meta])*
-            struct $reverse_iterator:ident;
-
-        // Stability of all generated items
-        stability:
-            $(#[$common_stability_attribute:meta])*
-
-        // Internal almost-iterator that is being delegated to
-        internal:
-            $internal_iterator:ident yielding ($iterty:ty);
-
-        // Kind of delegation - either single ended or double ended
-        delegate $($t:tt)*
-    } => {
-        $(#[$forward_iterator_attribute])*
-        $(#[$common_stability_attribute])*
-        pub struct $forward_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>);
-
-        $(#[$common_stability_attribute])*
-        impl<'a, P> fmt::Debug for $forward_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: fmt::Debug>,
-        {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                f.debug_tuple(stringify!($forward_iterator))
-                    .field(&self.0)
-                    .finish()
-            }
-        }
-
-        $(#[$common_stability_attribute])*
-        impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> {
-            type Item = $iterty;
-
-            #[inline]
-            fn next(&mut self) -> Option<$iterty> {
-                self.0.next()
-            }
-        }
-
-        $(#[$common_stability_attribute])*
-        impl<'a, P> Clone for $forward_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: Clone>,
-        {
-            fn clone(&self) -> Self {
-                $forward_iterator(self.0.clone())
-            }
-        }
-
-        $(#[$reverse_iterator_attribute])*
-        $(#[$common_stability_attribute])*
-        pub struct $reverse_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>);
-
-        $(#[$common_stability_attribute])*
-        impl<'a, P> fmt::Debug for $reverse_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: fmt::Debug>,
-        {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                f.debug_tuple(stringify!($reverse_iterator))
-                    .field(&self.0)
-                    .finish()
-            }
-        }
-
-        $(#[$common_stability_attribute])*
-        impl<'a, P> Iterator for $reverse_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
-        {
-            type Item = $iterty;
-
-            #[inline]
-            fn next(&mut self) -> Option<$iterty> {
-                self.0.next_back()
-            }
-        }
-
-        $(#[$common_stability_attribute])*
-        impl<'a, P> Clone for $reverse_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: Clone>,
-        {
-            fn clone(&self) -> Self {
-                $reverse_iterator(self.0.clone())
-            }
-        }
-
-        #[stable(feature = "fused", since = "1.26.0")]
-        impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {}
-
-        #[stable(feature = "fused", since = "1.26.0")]
-        impl<'a, P> FusedIterator for $reverse_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: ReverseSearcher<'a>>,
-        {}
-
-        generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*,
-                                                $forward_iterator,
-                                                $reverse_iterator, $iterty);
-    };
-    {
-        double ended; with $(#[$common_stability_attribute:meta])*,
-                           $forward_iterator:ident,
-                           $reverse_iterator:ident, $iterty:ty
-    } => {
-        $(#[$common_stability_attribute])*
-        impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
-        {
-            #[inline]
-            fn next_back(&mut self) -> Option<$iterty> {
-                self.0.next_back()
-            }
-        }
-
-        $(#[$common_stability_attribute])*
-        impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P>
-        where
-            P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>,
-        {
-            #[inline]
-            fn next_back(&mut self) -> Option<$iterty> {
-                self.0.next()
-            }
-        }
-    };
-    {
-        single ended; with $(#[$common_stability_attribute:meta])*,
-                           $forward_iterator:ident,
-                           $reverse_iterator:ident, $iterty:ty
-    } => {}
-}
-
-derive_pattern_clone! {
-    clone SplitInternal
-    with |s| SplitInternal { matcher: s.matcher.clone(), ..*s }
-}
-
-struct SplitInternal<'a, P: Pattern<'a>> {
-    start: usize,
-    end: usize,
-    matcher: P::Searcher,
-    allow_trailing_empty: bool,
-    finished: bool,
-}
-
-impl<'a, P> fmt::Debug for SplitInternal<'a, P>
-where
-    P: Pattern<'a, Searcher: fmt::Debug>,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitInternal")
-            .field("start", &self.start)
-            .field("end", &self.end)
-            .field("matcher", &self.matcher)
-            .field("allow_trailing_empty", &self.allow_trailing_empty)
-            .field("finished", &self.finished)
-            .finish()
-    }
-}
-
-impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
-    #[inline]
-    fn get_end(&mut self) -> Option<&'a str> {
-        if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) {
-            self.finished = true;
-            // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-            unsafe {
-                let string = self.matcher.haystack().get_unchecked(self.start..self.end);
-                Some(string)
-            }
-        } else {
-            None
-        }
-    }
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        if self.finished {
-            return None;
-        }
-
-        let haystack = self.matcher.haystack();
-        match self.matcher.next_match() {
-            // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries.
-            Some((a, b)) => unsafe {
-                let elt = haystack.get_unchecked(self.start..a);
-                self.start = b;
-                Some(elt)
-            },
-            None => self.get_end(),
-        }
-    }
-
-    #[inline]
-    fn next_inclusive(&mut self) -> Option<&'a str> {
-        if self.finished {
-            return None;
-        }
-
-        let haystack = self.matcher.haystack();
-        match self.matcher.next_match() {
-            // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
-            // and self.start is either the start of the original string,
-            // or `b` was assigned to it, so it also lies on unicode boundary.
-            Some((_, b)) => unsafe {
-                let elt = haystack.get_unchecked(self.start..b);
-                self.start = b;
-                Some(elt)
-            },
-            None => self.get_end(),
-        }
-    }
-
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str>
-    where
-        P::Searcher: ReverseSearcher<'a>,
-    {
-        if self.finished {
-            return None;
-        }
-
-        if !self.allow_trailing_empty {
-            self.allow_trailing_empty = true;
-            match self.next_back() {
-                Some(elt) if !elt.is_empty() => return Some(elt),
-                _ => {
-                    if self.finished {
-                        return None;
-                    }
-                }
-            }
-        }
-
-        let haystack = self.matcher.haystack();
-        match self.matcher.next_match_back() {
-            // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries.
-            Some((a, b)) => unsafe {
-                let elt = haystack.get_unchecked(b..self.end);
-                self.end = a;
-                Some(elt)
-            },
-            // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
-            None => unsafe {
-                self.finished = true;
-                Some(haystack.get_unchecked(self.start..self.end))
-            },
-        }
-    }
-
-    #[inline]
-    fn next_back_inclusive(&mut self) -> Option<&'a str>
-    where
-        P::Searcher: ReverseSearcher<'a>,
-    {
-        if self.finished {
-            return None;
-        }
-
-        if !self.allow_trailing_empty {
-            self.allow_trailing_empty = true;
-            match self.next_back_inclusive() {
-                Some(elt) if !elt.is_empty() => return Some(elt),
-                _ => {
-                    if self.finished {
-                        return None;
-                    }
-                }
-            }
-        }
-
-        let haystack = self.matcher.haystack();
-        match self.matcher.next_match_back() {
-            // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
-            // and self.end is either the end of the original string,
-            // or `b` was assigned to it, so it also lies on unicode boundary.
-            Some((_, b)) => unsafe {
-                let elt = haystack.get_unchecked(b..self.end);
-                self.end = b;
-                Some(elt)
-            },
-            // SAFETY: self.start is either the start of the original string,
-            // or start of a substring that represents the part of the string that hasn't
-            // iterated yet. Either way, it is guaranteed to lie on unicode boundary.
-            // self.end is either the end of the original string,
-            // or `b` was assigned to it, so it also lies on unicode boundary.
-            None => unsafe {
-                self.finished = true;
-                Some(haystack.get_unchecked(self.start..self.end))
-            },
-        }
-    }
-}
-
-generate_pattern_iterators! {
-    forward:
-        /// Created with the method [`split`].
-        ///
-        /// [`split`]: str::split
-        struct Split;
-    reverse:
-        /// Created with the method [`rsplit`].
-        ///
-        /// [`rsplit`]: str::rsplit
-        struct RSplit;
-    stability:
-        #[stable(feature = "rust1", since = "1.0.0")]
-    internal:
-        SplitInternal yielding (&'a str);
-    delegate double ended;
-}
-
-generate_pattern_iterators! {
-    forward:
-        /// Created with the method [`split_terminator`].
-        ///
-        /// [`split_terminator`]: str::split_terminator
-        struct SplitTerminator;
-    reverse:
-        /// Created with the method [`rsplit_terminator`].
-        ///
-        /// [`rsplit_terminator`]: str::rsplit_terminator
-        struct RSplitTerminator;
-    stability:
-        #[stable(feature = "rust1", since = "1.0.0")]
-    internal:
-        SplitInternal yielding (&'a str);
-    delegate double ended;
-}
-
-derive_pattern_clone! {
-    clone SplitNInternal
-    with |s| SplitNInternal { iter: s.iter.clone(), ..*s }
-}
-
-struct SplitNInternal<'a, P: Pattern<'a>> {
-    iter: SplitInternal<'a, P>,
-    /// The number of splits remaining
-    count: usize,
-}
-
-impl<'a, P> fmt::Debug for SplitNInternal<'a, P>
-where
-    P: Pattern<'a, Searcher: fmt::Debug>,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitNInternal")
-            .field("iter", &self.iter)
-            .field("count", &self.count)
-            .finish()
-    }
-}
-
-impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        match self.count {
-            0 => None,
-            1 => {
-                self.count = 0;
-                self.iter.get_end()
-            }
-            _ => {
-                self.count -= 1;
-                self.iter.next()
-            }
-        }
-    }
-
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str>
-    where
-        P::Searcher: ReverseSearcher<'a>,
-    {
-        match self.count {
-            0 => None,
-            1 => {
-                self.count = 0;
-                self.iter.get_end()
-            }
-            _ => {
-                self.count -= 1;
-                self.iter.next_back()
-            }
-        }
-    }
-}
-
-generate_pattern_iterators! {
-    forward:
-        /// Created with the method [`splitn`].
-        ///
-        /// [`splitn`]: str::splitn
-        struct SplitN;
-    reverse:
-        /// Created with the method [`rsplitn`].
-        ///
-        /// [`rsplitn`]: str::rsplitn
-        struct RSplitN;
-    stability:
-        #[stable(feature = "rust1", since = "1.0.0")]
-    internal:
-        SplitNInternal yielding (&'a str);
-    delegate single ended;
-}
-
-derive_pattern_clone! {
-    clone MatchIndicesInternal
-    with |s| MatchIndicesInternal(s.0.clone())
-}
-
-struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher);
-
-impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P>
-where
-    P: Pattern<'a, Searcher: fmt::Debug>,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("MatchIndicesInternal").field(&self.0).finish()
-    }
-}
-
-impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
-    #[inline]
-    fn next(&mut self) -> Option<(usize, &'a str)> {
-        self.0
-            .next_match()
-            // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
-            .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) })
-    }
-
-    #[inline]
-    fn next_back(&mut self) -> Option<(usize, &'a str)>
-    where
-        P::Searcher: ReverseSearcher<'a>,
-    {
-        self.0
-            .next_match_back()
-            // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
-            .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) })
-    }
-}
-
-generate_pattern_iterators! {
-    forward:
-        /// Created with the method [`match_indices`].
-        ///
-        /// [`match_indices`]: str::match_indices
-        struct MatchIndices;
-    reverse:
-        /// Created with the method [`rmatch_indices`].
-        ///
-        /// [`rmatch_indices`]: str::rmatch_indices
-        struct RMatchIndices;
-    stability:
-        #[stable(feature = "str_match_indices", since = "1.5.0")]
-    internal:
-        MatchIndicesInternal yielding ((usize, &'a str));
-    delegate double ended;
-}
-
-derive_pattern_clone! {
-    clone MatchesInternal
-    with |s| MatchesInternal(s.0.clone())
-}
-
-struct MatchesInternal<'a, P: Pattern<'a>>(P::Searcher);
-
-impl<'a, P> fmt::Debug for MatchesInternal<'a, P>
-where
-    P: Pattern<'a, Searcher: fmt::Debug>,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("MatchesInternal").field(&self.0).finish()
-    }
-}
-
-impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> {
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
-        self.0.next_match().map(|(a, b)| unsafe {
-            // Indices are known to be on utf8 boundaries
-            self.0.haystack().get_unchecked(a..b)
-        })
-    }
-
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str>
-    where
-        P::Searcher: ReverseSearcher<'a>,
-    {
-        // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries.
-        self.0.next_match_back().map(|(a, b)| unsafe {
-            // Indices are known to be on utf8 boundaries
-            self.0.haystack().get_unchecked(a..b)
-        })
-    }
-}
-
-generate_pattern_iterators! {
-    forward:
-        /// Created with the method [`matches`].
-        ///
-        /// [`matches`]: str::matches
-        struct Matches;
-    reverse:
-        /// Created with the method [`rmatches`].
-        ///
-        /// [`rmatches`]: str::rmatches
-        struct RMatches;
-    stability:
-        #[stable(feature = "str_matches", since = "1.2.0")]
-    internal:
-        MatchesInternal yielding (&'a str);
-    delegate double ended;
-}
-
-/// An iterator over the lines of a string, as string slices.
-///
-/// This struct is created with the [`lines`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`lines`]: str::lines
-#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone, Debug)]
-pub struct Lines<'a>(Map<SplitTerminator<'a, char>, LinesAnyMap>);
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Iterator for Lines<'a> {
-    type Item = &'a str;
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        self.0.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.0.size_hint()
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<&'a str> {
-        self.next_back()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> DoubleEndedIterator for Lines<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str> {
-        self.0.next_back()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl FusedIterator for Lines<'_> {}
-
-/// Created with the method [`lines_any`].
-///
-/// [`lines_any`]: str::lines_any
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
-#[derive(Clone, Debug)]
-#[allow(deprecated)]
-pub struct LinesAny<'a>(Lines<'a>);
-
-impl_fn_for_zst! {
-    /// A nameable, cloneable fn type
-    #[derive(Clone)]
-    struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str {
-        let l = line.len();
-        if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] }
-        else { line }
-    };
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-impl<'a> Iterator for LinesAny<'a> {
-    type Item = &'a str;
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        self.0.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.0.size_hint()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-impl<'a> DoubleEndedIterator for LinesAny<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str> {
-        self.0.next_back()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-#[allow(deprecated)]
-impl FusedIterator for LinesAny<'_> {}
-
-/*
-Section: UTF-8 validation
-*/
-
-// use truncation to fit u64 into usize
-const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
-
-/// Returns `true` if any byte in the word `x` is nonascii (>= 128).
-#[inline]
-fn contains_nonascii(x: usize) -> bool {
-    (x & NONASCII_MASK) != 0
-}
-
-/// Walks through `v` checking that it's a valid UTF-8 sequence,
-/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`.
-#[inline(always)]
-fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
-    let mut index = 0;
-    let len = v.len();
-
-    let usize_bytes = mem::size_of::<usize>();
-    let ascii_block_size = 2 * usize_bytes;
-    let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
-    let align = v.as_ptr().align_offset(usize_bytes);
-
-    while index < len {
-        let old_offset = index;
-        macro_rules! err {
-            ($error_len: expr) => {
-                return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len });
-            };
-        }
-
-        macro_rules! next {
-            () => {{
-                index += 1;
-                // we needed data, but there was none: error!
-                if index >= len {
-                    err!(None)
-                }
-                v[index]
-            }};
-        }
-
-        let first = v[index];
-        if first >= 128 {
-            let w = UTF8_CHAR_WIDTH[first as usize];
-            // 2-byte encoding is for codepoints  \u{0080} to  \u{07ff}
-            //        first  C2 80        last DF BF
-            // 3-byte encoding is for codepoints  \u{0800} to  \u{ffff}
-            //        first  E0 A0 80     last EF BF BF
-            //   excluding surrogates codepoints  \u{d800} to  \u{dfff}
-            //               ED A0 80 to       ED BF BF
-            // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff
-            //        first  F0 90 80 80  last F4 8F BF BF
-            //
-            // Use the UTF-8 syntax from the RFC
-            //
-            // https://tools.ietf.org/html/rfc3629
-            // UTF8-1      = %x00-7F
-            // UTF8-2      = %xC2-DF UTF8-tail
-            // UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
-            //               %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
-            // UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
-            //               %xF4 %x80-8F 2( UTF8-tail )
-            match w {
-                2 => {
-                    if next!() & !CONT_MASK != TAG_CONT_U8 {
-                        err!(Some(1))
-                    }
-                }
-                3 => {
-                    match (first, next!()) {
-                        (0xE0, 0xA0..=0xBF)
-                        | (0xE1..=0xEC, 0x80..=0xBF)
-                        | (0xED, 0x80..=0x9F)
-                        | (0xEE..=0xEF, 0x80..=0xBF) => {}
-                        _ => err!(Some(1)),
-                    }
-                    if next!() & !CONT_MASK != TAG_CONT_U8 {
-                        err!(Some(2))
-                    }
-                }
-                4 => {
-                    match (first, next!()) {
-                        (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {}
-                        _ => err!(Some(1)),
-                    }
-                    if next!() & !CONT_MASK != TAG_CONT_U8 {
-                        err!(Some(2))
-                    }
-                    if next!() & !CONT_MASK != TAG_CONT_U8 {
-                        err!(Some(3))
-                    }
-                }
-                _ => err!(Some(1)),
-            }
-            index += 1;
-        } else {
-            // Ascii case, try to skip forward quickly.
-            // When the pointer is aligned, read 2 words of data per iteration
-            // until we find a word containing a non-ascii byte.
-            if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 {
-                let ptr = v.as_ptr();
-                while index < blocks_end {
-                    // SAFETY: since `align - index` and `ascii_block_size` are
-                    // multiples of `usize_bytes`, `block = ptr.add(index)` is
-                    // always aligned with a `usize` so it's safe to dereference
-                    // both `block` and `block.offset(1)`.
-                    unsafe {
-                        let block = ptr.add(index) as *const usize;
-                        // break if there is a nonascii byte
-                        let zu = contains_nonascii(*block);
-                        let zv = contains_nonascii(*block.offset(1));
-                        if zu | zv {
-                            break;
-                        }
-                    }
-                    index += ascii_block_size;
-                }
-                // step from the point where the wordwise loop stopped
-                while index < len && v[index] < 128 {
-                    index += 1;
-                }
-            } else {
-                index += 1;
-            }
-        }
-    }
-
-    Ok(())
-}
-
-// https://tools.ietf.org/html/rfc3629
-static UTF8_CHAR_WIDTH: [u8; 256] = [
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, // 0x1F
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, // 0x3F
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, // 0x5F
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, // 0x7F
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, // 0x9F
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, // 0xBF
-    0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, // 0xDF
-    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
-    4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
-];
-
-/// Given a first byte, determines how many bytes are in this UTF-8 character.
-#[unstable(feature = "str_internals", issue = "none")]
-#[inline]
-pub fn utf8_char_width(b: u8) -> usize {
-    UTF8_CHAR_WIDTH[b as usize] as usize
-}
-
-/// Mask of the value bits of a continuation byte.
-const CONT_MASK: u8 = 0b0011_1111;
-/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte.
-const TAG_CONT_U8: u8 = 0b1000_0000;
-
-/*
-Section: Trait implementations
-*/
-
-mod traits {
-    use crate::cmp::Ordering;
-    use crate::ops;
-    use crate::ptr;
-    use crate::slice::SliceIndex;
-
-    /// Implements ordering of strings.
-    ///
-    /// Strings are ordered  lexicographically by their byte values. This orders Unicode code
-    /// points based on their positions in the code charts. This is not necessarily the same as
-    /// "alphabetical" order, which varies by language and locale. Sorting strings according to
-    /// culturally-accepted standards requires locale-specific data that is outside the scope of
-    /// the `str` type.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl Ord for str {
-        #[inline]
-        fn cmp(&self, other: &str) -> Ordering {
-            self.as_bytes().cmp(other.as_bytes())
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialEq for str {
-        #[inline]
-        fn eq(&self, other: &str) -> bool {
-            self.as_bytes() == other.as_bytes()
-        }
-        #[inline]
-        fn ne(&self, other: &str) -> bool {
-            !(*self).eq(other)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl Eq for str {}
-
-    /// Implements comparison operations on strings.
-    ///
-    /// Strings are compared lexicographically by their byte values. This compares Unicode code
-    /// points based on their positions in the code charts. This is not necessarily the same as
-    /// "alphabetical" order, which varies by language and locale. Comparing strings according to
-    /// culturally-accepted standards requires locale-specific data that is outside the scope of
-    /// the `str` type.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialOrd for str {
-        #[inline]
-        fn partial_cmp(&self, other: &str) -> Option<Ordering> {
-            Some(self.cmp(other))
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl<I> ops::Index<I> for str
-    where
-        I: SliceIndex<str>,
-    {
-        type Output = I::Output;
-
-        #[inline]
-        fn index(&self, index: I) -> &I::Output {
-            index.index(self)
-        }
-    }
-
-    #[stable(feature = "rust1", since = "1.0.0")]
-    impl<I> ops::IndexMut<I> for str
-    where
-        I: SliceIndex<str>,
-    {
-        #[inline]
-        fn index_mut(&mut self, index: I) -> &mut I::Output {
-            index.index_mut(self)
-        }
-    }
-
-    #[inline(never)]
-    #[cold]
-    #[track_caller]
-    fn str_index_overflow_fail() -> ! {
-        panic!("attempted to index str up to maximum usize");
-    }
-
-    /// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`.
-    ///
-    /// Returns a slice of the whole string, i.e., returns `&self` or `&mut
-    /// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike
-    /// other indexing operations, this can never panic.
-    ///
-    /// This operation is `O(1)`.
-    ///
-    /// Prior to 1.20.0, these indexing operations were still supported by
-    /// direct implementation of `Index` and `IndexMut`.
-    ///
-    /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe impl SliceIndex<str> for ops::RangeFull {
-        type Output = str;
-        #[inline]
-        fn get(self, slice: &str) -> Option<&Self::Output> {
-            Some(slice)
-        }
-        #[inline]
-        fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            Some(slice)
-        }
-        #[inline]
-        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-            slice
-        }
-        #[inline]
-        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-            slice
-        }
-        #[inline]
-        fn index(self, slice: &str) -> &Self::Output {
-            slice
-        }
-        #[inline]
-        fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            slice
-        }
-    }
-
-    /// Implements substring slicing with syntax `&self[begin .. end]` or `&mut
-    /// self[begin .. end]`.
-    ///
-    /// Returns a slice of the given string from the byte range
-    /// [`begin`, `end`).
-    ///
-    /// This operation is `O(1)`.
-    ///
-    /// Prior to 1.20.0, these indexing operations were still supported by
-    /// direct implementation of `Index` and `IndexMut`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `begin` or `end` does not point to the starting byte offset of
-    /// a character (as defined by `is_char_boundary`), if `begin > end`, or if
-    /// `end > len`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let s = "Löwe 老虎 Léopard";
-    /// assert_eq!(&s[0 .. 1], "L");
-    ///
-    /// assert_eq!(&s[1 .. 9], "öwe 老");
-    ///
-    /// // these will panic:
-    /// // byte 2 lies within `ö`:
-    /// // &s[2 ..3];
-    ///
-    /// // byte 8 lies within `老`
-    /// // &s[1 .. 8];
-    ///
-    /// // byte 100 is outside the string
-    /// // &s[3 .. 100];
-    /// ```
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe impl SliceIndex<str> for ops::Range<usize> {
-        type Output = str;
-        #[inline]
-        fn get(self, slice: &str) -> Option<&Self::Output> {
-            if self.start <= self.end
-                && slice.is_char_boundary(self.start)
-                && slice.is_char_boundary(self.end)
-            {
-                // SAFETY: just checked that `start` and `end` are on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                // We also checked char boundaries, so this is valid UTF-8.
-                Some(unsafe { &*self.get_unchecked(slice) })
-            } else {
-                None
-            }
-        }
-        #[inline]
-        fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if self.start <= self.end
-                && slice.is_char_boundary(self.start)
-                && slice.is_char_boundary(self.end)
-            {
-                // SAFETY: just checked that `start` and `end` are on a char boundary.
-                // We know the pointer is unique because we got it from `slice`.
-                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
-            } else {
-                None
-            }
-        }
-        #[inline]
-        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-            let slice = slice as *const [u8];
-            // SAFETY: the caller guarantees that `self` is in bounds of `slice`
-            // which satisfies all the conditions for `add`.
-            let ptr = unsafe { slice.as_ptr().add(self.start) };
-            let len = self.end - self.start;
-            ptr::slice_from_raw_parts(ptr, len) as *const str
-        }
-        #[inline]
-        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-            let slice = slice as *mut [u8];
-            // SAFETY: see comments for `get_unchecked`.
-            let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
-            let len = self.end - self.start;
-            ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
-        }
-        #[inline]
-        fn index(self, slice: &str) -> &Self::Output {
-            let (start, end) = (self.start, self.end);
-            match self.get(slice) {
-                Some(s) => s,
-                None => super::slice_error_fail(slice, start, end),
-            }
-        }
-        #[inline]
-        fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            // is_char_boundary checks that the index is in [0, .len()]
-            // cannot reuse `get` as above, because of NLL trouble
-            if self.start <= self.end
-                && slice.is_char_boundary(self.start)
-                && slice.is_char_boundary(self.end)
-            {
-                // SAFETY: just checked that `start` and `end` are on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                unsafe { &mut *self.get_unchecked_mut(slice) }
-            } else {
-                super::slice_error_fail(slice, self.start, self.end)
-            }
-        }
-    }
-
-    /// Implements substring slicing with syntax `&self[.. end]` or `&mut
-    /// self[.. end]`.
-    ///
-    /// Returns a slice of the given string from the byte range [`0`, `end`).
-    /// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`.
-    ///
-    /// This operation is `O(1)`.
-    ///
-    /// Prior to 1.20.0, these indexing operations were still supported by
-    /// direct implementation of `Index` and `IndexMut`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `end` does not point to the starting byte offset of a
-    /// character (as defined by `is_char_boundary`), or if `end > len`.
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
-        type Output = str;
-        #[inline]
-        fn get(self, slice: &str) -> Option<&Self::Output> {
-            if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                Some(unsafe { &*self.get_unchecked(slice) })
-            } else {
-                None
-            }
-        }
-        #[inline]
-        fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
-            } else {
-                None
-            }
-        }
-        #[inline]
-        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-            let slice = slice as *const [u8];
-            let ptr = slice.as_ptr();
-            ptr::slice_from_raw_parts(ptr, self.end) as *const str
-        }
-        #[inline]
-        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-            let slice = slice as *mut [u8];
-            let ptr = slice.as_mut_ptr();
-            ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str
-        }
-        #[inline]
-        fn index(self, slice: &str) -> &Self::Output {
-            let end = self.end;
-            match self.get(slice) {
-                Some(s) => s,
-                None => super::slice_error_fail(slice, 0, end),
-            }
-        }
-        #[inline]
-        fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            if slice.is_char_boundary(self.end) {
-                // SAFETY: just checked that `end` is on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                unsafe { &mut *self.get_unchecked_mut(slice) }
-            } else {
-                super::slice_error_fail(slice, 0, self.end)
-            }
-        }
-    }
-
-    /// Implements substring slicing with syntax `&self[begin ..]` or `&mut
-    /// self[begin ..]`.
-    ///
-    /// Returns a slice of the given string from the byte range [`begin`,
-    /// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin ..
-    /// len]`.
-    ///
-    /// This operation is `O(1)`.
-    ///
-    /// Prior to 1.20.0, these indexing operations were still supported by
-    /// direct implementation of `Index` and `IndexMut`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `begin` does not point to the starting byte offset of
-    /// a character (as defined by `is_char_boundary`), or if `begin > len`.
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
-        type Output = str;
-        #[inline]
-        fn get(self, slice: &str) -> Option<&Self::Output> {
-            if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                Some(unsafe { &*self.get_unchecked(slice) })
-            } else {
-                None
-            }
-        }
-        #[inline]
-        fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                Some(unsafe { &mut *self.get_unchecked_mut(slice) })
-            } else {
-                None
-            }
-        }
-        #[inline]
-        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-            let slice = slice as *const [u8];
-            // SAFETY: the caller guarantees that `self` is in bounds of `slice`
-            // which satisfies all the conditions for `add`.
-            let ptr = unsafe { slice.as_ptr().add(self.start) };
-            let len = slice.len() - self.start;
-            ptr::slice_from_raw_parts(ptr, len) as *const str
-        }
-        #[inline]
-        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-            let slice = slice as *mut [u8];
-            // SAFETY: identical to `get_unchecked`.
-            let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
-            let len = slice.len() - self.start;
-            ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
-        }
-        #[inline]
-        fn index(self, slice: &str) -> &Self::Output {
-            let (start, end) = (self.start, slice.len());
-            match self.get(slice) {
-                Some(s) => s,
-                None => super::slice_error_fail(slice, start, end),
-            }
-        }
-        #[inline]
-        fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            if slice.is_char_boundary(self.start) {
-                // SAFETY: just checked that `start` is on a char boundary,
-                // and we are passing in a safe reference, so the return value will also be one.
-                unsafe { &mut *self.get_unchecked_mut(slice) }
-            } else {
-                super::slice_error_fail(slice, self.start, slice.len())
-            }
-        }
-    }
-
-    /// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut
-    /// self[begin ..= end]`.
-    ///
-    /// Returns a slice of the given string from the byte range
-    /// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut
-    /// self[begin .. end + 1]`, except if `end` has the maximum value for
-    /// `usize`.
-    ///
-    /// This operation is `O(1)`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `begin` does not point to the starting byte offset of
-    /// a character (as defined by `is_char_boundary`), if `end` does not point
-    /// to the ending byte offset of a character (`end + 1` is either a starting
-    /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
-    #[stable(feature = "inclusive_range", since = "1.26.0")]
-    unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
-        type Output = str;
-        #[inline]
-        fn get(self, slice: &str) -> Option<&Self::Output> {
-            if *self.end() == usize::MAX {
-                None
-            } else {
-                (*self.start()..self.end() + 1).get(slice)
-            }
-        }
-        #[inline]
-        fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if *self.end() == usize::MAX {
-                None
-            } else {
-                (*self.start()..self.end() + 1).get_mut(slice)
-            }
-        }
-        #[inline]
-        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-            // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
-            unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
-        }
-        #[inline]
-        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-            // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
-            unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
-        }
-        #[inline]
-        fn index(self, slice: &str) -> &Self::Output {
-            if *self.end() == usize::MAX {
-                str_index_overflow_fail();
-            }
-            (*self.start()..self.end() + 1).index(slice)
-        }
-        #[inline]
-        fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            if *self.end() == usize::MAX {
-                str_index_overflow_fail();
-            }
-            (*self.start()..self.end() + 1).index_mut(slice)
-        }
-    }
-
-    /// Implements substring slicing with syntax `&self[..= end]` or `&mut
-    /// self[..= end]`.
-    ///
-    /// Returns a slice of the given string from the byte range [0, `end`].
-    /// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum
-    /// value for `usize`.
-    ///
-    /// This operation is `O(1)`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `end` does not point to the ending byte offset of a character
-    /// (`end + 1` is either a starting byte offset as defined by
-    /// `is_char_boundary`, or equal to `len`), or if `end >= len`.
-    #[stable(feature = "inclusive_range", since = "1.26.0")]
-    unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
-        type Output = str;
-        #[inline]
-        fn get(self, slice: &str) -> Option<&Self::Output> {
-            if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) }
-        }
-        #[inline]
-        fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-            if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) }
-        }
-        #[inline]
-        unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-            // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
-            unsafe { (..self.end + 1).get_unchecked(slice) }
-        }
-        #[inline]
-        unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-            // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
-            unsafe { (..self.end + 1).get_unchecked_mut(slice) }
-        }
-        #[inline]
-        fn index(self, slice: &str) -> &Self::Output {
-            if self.end == usize::MAX {
-                str_index_overflow_fail();
-            }
-            (..self.end + 1).index(slice)
-        }
-        #[inline]
-        fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-            if self.end == usize::MAX {
-                str_index_overflow_fail();
-            }
-            (..self.end + 1).index_mut(slice)
-        }
-    }
-}
-
-// truncate `&str` to length at most equal to `max`
-// return `true` if it were truncated, and the new str.
-fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
-    if max >= s.len() {
-        (false, s)
-    } else {
-        while !s.is_char_boundary(max) {
-            max -= 1;
-        }
-        (true, &s[..max])
-    }
-}
+use validations::truncate_to_char_boundary;
 
 #[inline(never)]
 #[cold]
@@ -4549,22 +2413,6 @@
     }
 }
 
-impl_fn_for_zst! {
-    #[derive(Clone)]
-    struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug {
-        c.escape_debug_ext(false)
-    };
-
-    #[derive(Clone)]
-    struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode {
-        c.escape_unicode()
-    };
-    #[derive(Clone)]
-    struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault {
-        c.escape_default()
-    };
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<[u8]> for str {
     #[inline]
@@ -4590,45 +2438,29 @@
     }
 }
 
-/// An iterator over the non-whitespace substrings of a string,
-/// separated by any amount of whitespace.
-///
-/// This struct is created by the [`split_whitespace`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`split_whitespace`]: str::split_whitespace
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-#[derive(Clone, Debug)]
-pub struct SplitWhitespace<'a> {
-    inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>,
-}
-
-/// An iterator over the non-ASCII-whitespace substrings of a string,
-/// separated by any amount of ASCII whitespace.
-///
-/// This struct is created by the [`split_ascii_whitespace`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`split_ascii_whitespace`]: str::split_ascii_whitespace
-#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
-#[derive(Clone, Debug)]
-pub struct SplitAsciiWhitespace<'a> {
-    inner: Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty>, UnsafeBytesToStr>,
-}
-
-/// An iterator over the substrings of a string,
-/// terminated by a substring matching to a predicate function
-/// Unlike `Split`, it contains the matched part as a terminator
-/// of the subslice.
-///
-/// This struct is created by the [`split_inclusive`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`split_inclusive`]: str::split_inclusive
-#[unstable(feature = "split_inclusive", issue = "72360")]
-pub struct SplitInclusive<'a, P: Pattern<'a>>(SplitInternal<'a, P>);
-
 impl_fn_for_zst! {
+    /// A nameable, cloneable fn type
+    #[derive(Clone)]
+    struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str {
+        let l = line.len();
+        if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] }
+        else { line }
+    };
+
+    #[derive(Clone)]
+    struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug {
+        c.escape_debug_ext(false)
+    };
+
+    #[derive(Clone)]
+    struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode {
+        c.escape_unicode()
+    };
+    #[derive(Clone)]
+    struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault {
+        c.escape_default()
+    };
+
     #[derive(Clone)]
     struct IsWhitespace impl Fn = |c: char| -> bool {
         c.is_whitespace()
@@ -4655,223 +2487,3 @@
         unsafe { from_utf8_unchecked(bytes) }
     };
 }
-
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-impl<'a> Iterator for SplitWhitespace<'a> {
-    type Item = &'a str;
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        self.inner.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.inner.size_hint()
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<&'a str> {
-        self.next_back()
-    }
-}
-
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str> {
-        self.inner.next_back()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl FusedIterator for SplitWhitespace<'_> {}
-
-#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
-impl<'a> Iterator for SplitAsciiWhitespace<'a> {
-    type Item = &'a str;
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        self.inner.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.inner.size_hint()
-    }
-
-    #[inline]
-    fn last(mut self) -> Option<&'a str> {
-        self.next_back()
-    }
-}
-
-#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
-impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> {
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str> {
-        self.inner.next_back()
-    }
-}
-
-#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
-impl FusedIterator for SplitAsciiWhitespace<'_> {}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
-    type Item = &'a str;
-
-    #[inline]
-    fn next(&mut self) -> Option<&'a str> {
-        self.0.next_inclusive()
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("SplitInclusive").field("0", &self.0).finish()
-    }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> {
-    fn clone(&self) -> Self {
-        SplitInclusive(self.0.clone())
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
-    for SplitInclusive<'a, P>
-{
-    #[inline]
-    fn next_back(&mut self) -> Option<&'a str> {
-        self.0.next_back_inclusive()
-    }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
-
-/// An iterator of [`u16`] over the string encoded as UTF-16.
-///
-/// This struct is created by the [`encode_utf16`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`encode_utf16`]: str::encode_utf16
-#[derive(Clone)]
-#[stable(feature = "encode_utf16", since = "1.8.0")]
-pub struct EncodeUtf16<'a> {
-    chars: Chars<'a>,
-    extra: u16,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl fmt::Debug for EncodeUtf16<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.pad("EncodeUtf16 { .. }")
-    }
-}
-
-#[stable(feature = "encode_utf16", since = "1.8.0")]
-impl<'a> Iterator for EncodeUtf16<'a> {
-    type Item = u16;
-
-    #[inline]
-    fn next(&mut self) -> Option<u16> {
-        if self.extra != 0 {
-            let tmp = self.extra;
-            self.extra = 0;
-            return Some(tmp);
-        }
-
-        let mut buf = [0; 2];
-        self.chars.next().map(|ch| {
-            let n = ch.encode_utf16(&mut buf).len();
-            if n == 2 {
-                self.extra = buf[1];
-            }
-            buf[0]
-        })
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (low, high) = self.chars.size_hint();
-        // every char gets either one u16 or two u16,
-        // so this iterator is between 1 or 2 times as
-        // long as the underlying iterator.
-        (low, high.and_then(|n| n.checked_mul(2)))
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl FusedIterator for EncodeUtf16<'_> {}
-
-/// The return type of [`str::escape_debug`].
-#[stable(feature = "str_escape", since = "1.34.0")]
-#[derive(Clone, Debug)]
-pub struct EscapeDebug<'a> {
-    inner: Chain<
-        Flatten<option::IntoIter<char::EscapeDebug>>,
-        FlatMap<Chars<'a>, char::EscapeDebug, CharEscapeDebugContinue>,
-    >,
-}
-
-/// The return type of [`str::escape_default`].
-#[stable(feature = "str_escape", since = "1.34.0")]
-#[derive(Clone, Debug)]
-pub struct EscapeDefault<'a> {
-    inner: FlatMap<Chars<'a>, char::EscapeDefault, CharEscapeDefault>,
-}
-
-/// The return type of [`str::escape_unicode`].
-#[stable(feature = "str_escape", since = "1.34.0")]
-#[derive(Clone, Debug)]
-pub struct EscapeUnicode<'a> {
-    inner: FlatMap<Chars<'a>, char::EscapeUnicode, CharEscapeUnicode>,
-}
-
-macro_rules! escape_types_impls {
-    ($( $Name: ident ),+) => {$(
-        #[stable(feature = "str_escape", since = "1.34.0")]
-        impl<'a> fmt::Display for $Name<'a> {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                self.clone().try_for_each(|c| f.write_char(c))
-            }
-        }
-
-        #[stable(feature = "str_escape", since = "1.34.0")]
-        impl<'a> Iterator for $Name<'a> {
-            type Item = char;
-
-            #[inline]
-            fn next(&mut self) -> Option<char> { self.inner.next() }
-
-            #[inline]
-            fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
-
-            #[inline]
-            fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
-                Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
-            {
-                self.inner.try_fold(init, fold)
-            }
-
-            #[inline]
-            fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
-                where Fold: FnMut(Acc, Self::Item) -> Acc,
-            {
-                self.inner.fold(init, fold)
-            }
-        }
-
-        #[stable(feature = "str_escape", since = "1.34.0")]
-        impl<'a> FusedIterator for $Name<'a> {}
-    )+}
-}
-
-escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode);
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
new file mode 100644
index 0000000..af1ce00
--- /dev/null
+++ b/library/core/src/str/traits.rs
@@ -0,0 +1,597 @@
+//! Trait implementations for `str`.
+
+use crate::cmp::Ordering;
+use crate::ops;
+use crate::ptr;
+use crate::slice::SliceIndex;
+
+use super::ParseBoolError;
+
+/// Implements ordering of strings.
+///
+/// Strings are ordered  lexicographically by their byte values. This orders Unicode code
+/// points based on their positions in the code charts. This is not necessarily the same as
+/// "alphabetical" order, which varies by language and locale. Sorting strings according to
+/// culturally-accepted standards requires locale-specific data that is outside the scope of
+/// the `str` type.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for str {
+    #[inline]
+    fn cmp(&self, other: &str) -> Ordering {
+        self.as_bytes().cmp(other.as_bytes())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for str {
+    #[inline]
+    fn eq(&self, other: &str) -> bool {
+        self.as_bytes() == other.as_bytes()
+    }
+    #[inline]
+    fn ne(&self, other: &str) -> bool {
+        !(*self).eq(other)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for str {}
+
+/// Implements comparison operations on strings.
+///
+/// Strings are compared lexicographically by their byte values. This compares Unicode code
+/// points based on their positions in the code charts. This is not necessarily the same as
+/// "alphabetical" order, which varies by language and locale. Comparing strings according to
+/// culturally-accepted standards requires locale-specific data that is outside the scope of
+/// the `str` type.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for str {
+    #[inline]
+    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> ops::Index<I> for str
+where
+    I: SliceIndex<str>,
+{
+    type Output = I::Output;
+
+    #[inline]
+    fn index(&self, index: I) -> &I::Output {
+        index.index(self)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I> ops::IndexMut<I> for str
+where
+    I: SliceIndex<str>,
+{
+    #[inline]
+    fn index_mut(&mut self, index: I) -> &mut I::Output {
+        index.index_mut(self)
+    }
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+fn str_index_overflow_fail() -> ! {
+    panic!("attempted to index str up to maximum usize");
+}
+
+/// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`.
+///
+/// Returns a slice of the whole string, i.e., returns `&self` or `&mut
+/// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike
+/// other indexing operations, this can never panic.
+///
+/// This operation is *O*(1).
+///
+/// Prior to 1.20.0, these indexing operations were still supported by
+/// direct implementation of `Index` and `IndexMut`.
+///
+/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
+#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+unsafe impl SliceIndex<str> for ops::RangeFull {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        Some(slice)
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        Some(slice)
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        slice
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        slice
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        slice
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        slice
+    }
+}
+
+/// Implements substring slicing with syntax `&self[begin .. end]` or `&mut
+/// self[begin .. end]`.
+///
+/// Returns a slice of the given string from the byte range
+/// [`begin`, `end`).
+///
+/// This operation is *O*(1).
+///
+/// Prior to 1.20.0, these indexing operations were still supported by
+/// direct implementation of `Index` and `IndexMut`.
+///
+/// # Panics
+///
+/// Panics if `begin` or `end` does not point to the starting byte offset of
+/// a character (as defined by `is_char_boundary`), if `begin > end`, or if
+/// `end > len`.
+///
+/// # Examples
+///
+/// ```
+/// let s = "Löwe 老虎 Léopard";
+/// assert_eq!(&s[0 .. 1], "L");
+///
+/// assert_eq!(&s[1 .. 9], "öwe 老");
+///
+/// // these will panic:
+/// // byte 2 lies within `ö`:
+/// // &s[2 ..3];
+///
+/// // byte 8 lies within `老`
+/// // &s[1 .. 8];
+///
+/// // byte 100 is outside the string
+/// // &s[3 .. 100];
+/// ```
+#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+unsafe impl SliceIndex<str> for ops::Range<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if self.start <= self.end
+            && slice.is_char_boundary(self.start)
+            && slice.is_char_boundary(self.end)
+        {
+            // SAFETY: just checked that `start` and `end` are on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            // We also checked char boundaries, so this is valid UTF-8.
+            Some(unsafe { &*self.get_unchecked(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if self.start <= self.end
+            && slice.is_char_boundary(self.start)
+            && slice.is_char_boundary(self.end)
+        {
+            // SAFETY: just checked that `start` and `end` are on a char boundary.
+            // We know the pointer is unique because we got it from `slice`.
+            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        let slice = slice as *const [u8];
+        // SAFETY: the caller guarantees that `self` is in bounds of `slice`
+        // which satisfies all the conditions for `add`.
+        let ptr = unsafe { slice.as_ptr().add(self.start) };
+        let len = self.end - self.start;
+        ptr::slice_from_raw_parts(ptr, len) as *const str
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        let slice = slice as *mut [u8];
+        // SAFETY: see comments for `get_unchecked`.
+        let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
+        let len = self.end - self.start;
+        ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        let (start, end) = (self.start, self.end);
+        match self.get(slice) {
+            Some(s) => s,
+            None => super::slice_error_fail(slice, start, end),
+        }
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        // is_char_boundary checks that the index is in [0, .len()]
+        // cannot reuse `get` as above, because of NLL trouble
+        if self.start <= self.end
+            && slice.is_char_boundary(self.start)
+            && slice.is_char_boundary(self.end)
+        {
+            // SAFETY: just checked that `start` and `end` are on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            unsafe { &mut *self.get_unchecked_mut(slice) }
+        } else {
+            super::slice_error_fail(slice, self.start, self.end)
+        }
+    }
+}
+
+/// Implements substring slicing with syntax `&self[.. end]` or `&mut
+/// self[.. end]`.
+///
+/// Returns a slice of the given string from the byte range [`0`, `end`).
+/// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`.
+///
+/// This operation is *O*(1).
+///
+/// Prior to 1.20.0, these indexing operations were still supported by
+/// direct implementation of `Index` and `IndexMut`.
+///
+/// # Panics
+///
+/// Panics if `end` does not point to the starting byte offset of a
+/// character (as defined by `is_char_boundary`), or if `end > len`.
+#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+unsafe impl SliceIndex<str> for ops::RangeTo<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if slice.is_char_boundary(self.end) {
+            // SAFETY: just checked that `end` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            Some(unsafe { &*self.get_unchecked(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if slice.is_char_boundary(self.end) {
+            // SAFETY: just checked that `end` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        let slice = slice as *const [u8];
+        let ptr = slice.as_ptr();
+        ptr::slice_from_raw_parts(ptr, self.end) as *const str
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        let slice = slice as *mut [u8];
+        let ptr = slice.as_mut_ptr();
+        ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        let end = self.end;
+        match self.get(slice) {
+            Some(s) => s,
+            None => super::slice_error_fail(slice, 0, end),
+        }
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        if slice.is_char_boundary(self.end) {
+            // SAFETY: just checked that `end` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            unsafe { &mut *self.get_unchecked_mut(slice) }
+        } else {
+            super::slice_error_fail(slice, 0, self.end)
+        }
+    }
+}
+
+/// Implements substring slicing with syntax `&self[begin ..]` or `&mut
+/// self[begin ..]`.
+///
+/// Returns a slice of the given string from the byte range [`begin`,
+/// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin ..
+/// len]`.
+///
+/// This operation is *O*(1).
+///
+/// Prior to 1.20.0, these indexing operations were still supported by
+/// direct implementation of `Index` and `IndexMut`.
+///
+/// # Panics
+///
+/// Panics if `begin` does not point to the starting byte offset of
+/// a character (as defined by `is_char_boundary`), or if `begin > len`.
+#[stable(feature = "str_checked_slicing", since = "1.20.0")]
+unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if slice.is_char_boundary(self.start) {
+            // SAFETY: just checked that `start` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            Some(unsafe { &*self.get_unchecked(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if slice.is_char_boundary(self.start) {
+            // SAFETY: just checked that `start` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            Some(unsafe { &mut *self.get_unchecked_mut(slice) })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        let slice = slice as *const [u8];
+        // SAFETY: the caller guarantees that `self` is in bounds of `slice`
+        // which satisfies all the conditions for `add`.
+        let ptr = unsafe { slice.as_ptr().add(self.start) };
+        let len = slice.len() - self.start;
+        ptr::slice_from_raw_parts(ptr, len) as *const str
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        let slice = slice as *mut [u8];
+        // SAFETY: identical to `get_unchecked`.
+        let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
+        let len = slice.len() - self.start;
+        ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        let (start, end) = (self.start, slice.len());
+        match self.get(slice) {
+            Some(s) => s,
+            None => super::slice_error_fail(slice, start, end),
+        }
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        if slice.is_char_boundary(self.start) {
+            // SAFETY: just checked that `start` is on a char boundary,
+            // and we are passing in a safe reference, so the return value will also be one.
+            unsafe { &mut *self.get_unchecked_mut(slice) }
+        } else {
+            super::slice_error_fail(slice, self.start, slice.len())
+        }
+    }
+}
+
+/// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut
+/// self[begin ..= end]`.
+///
+/// Returns a slice of the given string from the byte range
+/// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut
+/// self[begin .. end + 1]`, except if `end` has the maximum value for
+/// `usize`.
+///
+/// This operation is *O*(1).
+///
+/// # Panics
+///
+/// Panics if `begin` does not point to the starting byte offset of
+/// a character (as defined by `is_char_boundary`), if `end` does not point
+/// to the ending byte offset of a character (`end + 1` is either a starting
+/// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+unsafe impl SliceIndex<str> for ops::RangeInclusive<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if *self.end() == usize::MAX {
+            None
+        } else {
+            (*self.start()..self.end() + 1).get_mut(slice)
+        }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
+        unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        if *self.end() == usize::MAX {
+            str_index_overflow_fail();
+        }
+        (*self.start()..self.end() + 1).index(slice)
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        if *self.end() == usize::MAX {
+            str_index_overflow_fail();
+        }
+        (*self.start()..self.end() + 1).index_mut(slice)
+    }
+}
+
+/// Implements substring slicing with syntax `&self[..= end]` or `&mut
+/// self[..= end]`.
+///
+/// Returns a slice of the given string from the byte range [0, `end`].
+/// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum
+/// value for `usize`.
+///
+/// This operation is *O*(1).
+///
+/// # Panics
+///
+/// Panics if `end` does not point to the ending byte offset of a character
+/// (`end + 1` is either a starting byte offset as defined by
+/// `is_char_boundary`, or equal to `len`), or if `end >= len`.
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+unsafe impl SliceIndex<str> for ops::RangeToInclusive<usize> {
+    type Output = str;
+    #[inline]
+    fn get(self, slice: &str) -> Option<&Self::Output> {
+        if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) }
+    }
+    #[inline]
+    fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
+        if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) }
+    }
+    #[inline]
+    unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
+        unsafe { (..self.end + 1).get_unchecked(slice) }
+    }
+    #[inline]
+    unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
+        // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (..self.end + 1).get_unchecked_mut(slice) }
+    }
+    #[inline]
+    fn index(self, slice: &str) -> &Self::Output {
+        if self.end == usize::MAX {
+            str_index_overflow_fail();
+        }
+        (..self.end + 1).index(slice)
+    }
+    #[inline]
+    fn index_mut(self, slice: &mut str) -> &mut Self::Output {
+        if self.end == usize::MAX {
+            str_index_overflow_fail();
+        }
+        (..self.end + 1).index_mut(slice)
+    }
+}
+
+/// Parse a value from a string
+///
+/// `FromStr`'s [`from_str`] method is often used implicitly, through
+/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples.
+///
+/// [`from_str`]: FromStr::from_str
+/// [`parse`]: str::parse
+///
+/// `FromStr` does not have a lifetime parameter, and so you can only parse types
+/// that do not contain a lifetime parameter themselves. In other words, you can
+/// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that
+/// contains an `i32`, but not one that contains an `&i32`.
+///
+/// # Examples
+///
+/// Basic implementation of `FromStr` on an example `Point` type:
+///
+/// ```
+/// use std::str::FromStr;
+/// use std::num::ParseIntError;
+///
+/// #[derive(Debug, PartialEq)]
+/// struct Point {
+///     x: i32,
+///     y: i32
+/// }
+///
+/// impl FromStr for Point {
+///     type Err = ParseIntError;
+///
+///     fn from_str(s: &str) -> Result<Self, Self::Err> {
+///         let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
+///                                  .split(',')
+///                                  .collect();
+///
+///         let x_fromstr = coords[0].parse::<i32>()?;
+///         let y_fromstr = coords[1].parse::<i32>()?;
+///
+///         Ok(Point { x: x_fromstr, y: y_fromstr })
+///     }
+/// }
+///
+/// let p = Point::from_str("(1,2)");
+/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} )
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait FromStr: Sized {
+    /// The associated error which can be returned from parsing.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    type Err;
+
+    /// Parses a string `s` to return a value of this type.
+    ///
+    /// If parsing succeeds, return the value inside [`Ok`], otherwise
+    /// when the string is ill-formatted return an error specific to the
+    /// inside [`Err`]. The error type is specific to implementation of the trait.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`:
+    ///
+    /// [ithirtytwo]: ../../std/primitive.i32.html
+    ///
+    /// ```
+    /// use std::str::FromStr;
+    ///
+    /// let s = "5";
+    /// let x = i32::from_str(s).unwrap();
+    ///
+    /// assert_eq!(5, x);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_str(s: &str) -> Result<Self, Self::Err>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl FromStr for bool {
+    type Err = ParseBoolError;
+
+    /// Parse a `bool` from a string.
+    ///
+    /// Yields a `Result<bool, ParseBoolError>`, because `s` may or may not
+    /// actually be parseable.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::str::FromStr;
+    ///
+    /// assert_eq!(FromStr::from_str("true"), Ok(true));
+    /// assert_eq!(FromStr::from_str("false"), Ok(false));
+    /// assert!(<bool as FromStr>::from_str("not even a boolean").is_err());
+    /// ```
+    ///
+    /// Note, in many cases, the `.parse()` method on `str` is more proper.
+    ///
+    /// ```
+    /// assert_eq!("true".parse(), Ok(true));
+    /// assert_eq!("false".parse(), Ok(false));
+    /// assert!("not even a boolean".parse::<bool>().is_err());
+    /// ```
+    #[inline]
+    fn from_str(s: &str) -> Result<bool, ParseBoolError> {
+        match s {
+            "true" => Ok(true),
+            "false" => Ok(false),
+            _ => Err(ParseBoolError { _priv: () }),
+        }
+    }
+}
diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs
new file mode 100644
index 0000000..10cf1e1
--- /dev/null
+++ b/library/core/src/str/validations.rs
@@ -0,0 +1,275 @@
+//! Operations related to UTF-8 validation.
+
+use crate::mem;
+
+use super::Utf8Error;
+
+/// Returns the initial codepoint accumulator for the first byte.
+/// The first byte is special, only want bottom 5 bits for width 2, 4 bits
+/// for width 3, and 3 bits for width 4.
+#[inline]
+fn utf8_first_byte(byte: u8, width: u32) -> u32 {
+    (byte & (0x7F >> width)) as u32
+}
+
+/// Returns the value of `ch` updated with continuation byte `byte`.
+#[inline]
+fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 {
+    (ch << 6) | (byte & CONT_MASK) as u32
+}
+
+/// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the
+/// bits `10`).
+#[inline]
+pub(super) fn utf8_is_cont_byte(byte: u8) -> bool {
+    (byte & !CONT_MASK) == TAG_CONT_U8
+}
+
+#[inline]
+fn unwrap_or_0(opt: Option<&u8>) -> u8 {
+    match opt {
+        Some(&byte) => byte,
+        None => 0,
+    }
+}
+
+/// Reads the next code point out of a byte iterator (assuming a
+/// UTF-8-like encoding).
+#[unstable(feature = "str_internals", issue = "none")]
+#[inline]
+pub fn next_code_point<'a, I: Iterator<Item = &'a u8>>(bytes: &mut I) -> Option<u32> {
+    // Decode UTF-8
+    let x = *bytes.next()?;
+    if x < 128 {
+        return Some(x as u32);
+    }
+
+    // Multibyte case follows
+    // Decode from a byte combination out of: [[[x y] z] w]
+    // NOTE: Performance is sensitive to the exact formulation here
+    let init = utf8_first_byte(x, 2);
+    let y = unwrap_or_0(bytes.next());
+    let mut ch = utf8_acc_cont_byte(init, y);
+    if x >= 0xE0 {
+        // [[x y z] w] case
+        // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid
+        let z = unwrap_or_0(bytes.next());
+        let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
+        ch = init << 12 | y_z;
+        if x >= 0xF0 {
+            // [x y z w] case
+            // use only the lower 3 bits of `init`
+            let w = unwrap_or_0(bytes.next());
+            ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
+        }
+    }
+
+    Some(ch)
+}
+
+/// Reads the last code point out of a byte iterator (assuming a
+/// UTF-8-like encoding).
+#[inline]
+pub(super) fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option<u32>
+where
+    I: DoubleEndedIterator<Item = &'a u8>,
+{
+    // Decode UTF-8
+    let w = match *bytes.next_back()? {
+        next_byte if next_byte < 128 => return Some(next_byte as u32),
+        back_byte => back_byte,
+    };
+
+    // Multibyte case follows
+    // Decode from a byte combination out of: [x [y [z w]]]
+    let mut ch;
+    let z = unwrap_or_0(bytes.next_back());
+    ch = utf8_first_byte(z, 2);
+    if utf8_is_cont_byte(z) {
+        let y = unwrap_or_0(bytes.next_back());
+        ch = utf8_first_byte(y, 3);
+        if utf8_is_cont_byte(y) {
+            let x = unwrap_or_0(bytes.next_back());
+            ch = utf8_first_byte(x, 4);
+            ch = utf8_acc_cont_byte(ch, y);
+        }
+        ch = utf8_acc_cont_byte(ch, z);
+    }
+    ch = utf8_acc_cont_byte(ch, w);
+
+    Some(ch)
+}
+
+// use truncation to fit u64 into usize
+const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
+
+/// Returns `true` if any byte in the word `x` is nonascii (>= 128).
+#[inline]
+fn contains_nonascii(x: usize) -> bool {
+    (x & NONASCII_MASK) != 0
+}
+
+/// Walks through `v` checking that it's a valid UTF-8 sequence,
+/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`.
+#[inline(always)]
+pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
+    let mut index = 0;
+    let len = v.len();
+
+    let usize_bytes = mem::size_of::<usize>();
+    let ascii_block_size = 2 * usize_bytes;
+    let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
+    let align = v.as_ptr().align_offset(usize_bytes);
+
+    while index < len {
+        let old_offset = index;
+        macro_rules! err {
+            ($error_len: expr) => {
+                return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len });
+            };
+        }
+
+        macro_rules! next {
+            () => {{
+                index += 1;
+                // we needed data, but there was none: error!
+                if index >= len {
+                    err!(None)
+                }
+                v[index]
+            }};
+        }
+
+        let first = v[index];
+        if first >= 128 {
+            let w = UTF8_CHAR_WIDTH[first as usize];
+            // 2-byte encoding is for codepoints  \u{0080} to  \u{07ff}
+            //        first  C2 80        last DF BF
+            // 3-byte encoding is for codepoints  \u{0800} to  \u{ffff}
+            //        first  E0 A0 80     last EF BF BF
+            //   excluding surrogates codepoints  \u{d800} to  \u{dfff}
+            //               ED A0 80 to       ED BF BF
+            // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff
+            //        first  F0 90 80 80  last F4 8F BF BF
+            //
+            // Use the UTF-8 syntax from the RFC
+            //
+            // https://tools.ietf.org/html/rfc3629
+            // UTF8-1      = %x00-7F
+            // UTF8-2      = %xC2-DF UTF8-tail
+            // UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
+            //               %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
+            // UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
+            //               %xF4 %x80-8F 2( UTF8-tail )
+            match w {
+                2 => {
+                    if next!() & !CONT_MASK != TAG_CONT_U8 {
+                        err!(Some(1))
+                    }
+                }
+                3 => {
+                    match (first, next!()) {
+                        (0xE0, 0xA0..=0xBF)
+                        | (0xE1..=0xEC, 0x80..=0xBF)
+                        | (0xED, 0x80..=0x9F)
+                        | (0xEE..=0xEF, 0x80..=0xBF) => {}
+                        _ => err!(Some(1)),
+                    }
+                    if next!() & !CONT_MASK != TAG_CONT_U8 {
+                        err!(Some(2))
+                    }
+                }
+                4 => {
+                    match (first, next!()) {
+                        (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {}
+                        _ => err!(Some(1)),
+                    }
+                    if next!() & !CONT_MASK != TAG_CONT_U8 {
+                        err!(Some(2))
+                    }
+                    if next!() & !CONT_MASK != TAG_CONT_U8 {
+                        err!(Some(3))
+                    }
+                }
+                _ => err!(Some(1)),
+            }
+            index += 1;
+        } else {
+            // Ascii case, try to skip forward quickly.
+            // When the pointer is aligned, read 2 words of data per iteration
+            // until we find a word containing a non-ascii byte.
+            if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 {
+                let ptr = v.as_ptr();
+                while index < blocks_end {
+                    // SAFETY: since `align - index` and `ascii_block_size` are
+                    // multiples of `usize_bytes`, `block = ptr.add(index)` is
+                    // always aligned with a `usize` so it's safe to dereference
+                    // both `block` and `block.offset(1)`.
+                    unsafe {
+                        let block = ptr.add(index) as *const usize;
+                        // break if there is a nonascii byte
+                        let zu = contains_nonascii(*block);
+                        let zv = contains_nonascii(*block.offset(1));
+                        if zu | zv {
+                            break;
+                        }
+                    }
+                    index += ascii_block_size;
+                }
+                // step from the point where the wordwise loop stopped
+                while index < len && v[index] < 128 {
+                    index += 1;
+                }
+            } else {
+                index += 1;
+            }
+        }
+    }
+
+    Ok(())
+}
+
+// https://tools.ietf.org/html/rfc3629
+static UTF8_CHAR_WIDTH: [u8; 256] = [
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, // 0x1F
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, // 0x3F
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, // 0x5F
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, // 0x7F
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, // 0x9F
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, // 0xBF
+    0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, // 0xDF
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
+    4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
+];
+
+/// Given a first byte, determines how many bytes are in this UTF-8 character.
+#[unstable(feature = "str_internals", issue = "none")]
+#[inline]
+pub fn utf8_char_width(b: u8) -> usize {
+    UTF8_CHAR_WIDTH[b as usize] as usize
+}
+
+/// Mask of the value bits of a continuation byte.
+const CONT_MASK: u8 = 0b0011_1111;
+/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte.
+const TAG_CONT_U8: u8 = 0b1000_0000;
+
+// truncate `&str` to length at most equal to `max`
+// return `true` if it were truncated, and the new str.
+pub(super) fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
+    if max >= s.len() {
+        (false, s)
+    } else {
+        while !s.is_char_boundary(max) {
+            max -= 1;
+        }
+        (true, &s[..max])
+    }
+}
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 668a028..8cca9dc 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -129,13 +129,8 @@
     /// associated task.
     #[rustc_promotable]
     #[stable(feature = "futures_api", since = "1.36.0")]
-    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
-    // without first consulting with T-Lang.
-    //
-    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
-    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
-    #[rustc_allow_const_fn_ptr]
     #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
+    #[allow_internal_unstable(const_fn_fn_ptr_basics)]
     pub const fn new(
         clone: unsafe fn(*const ()) -> RawWaker,
         wake: unsafe fn(*const ()),
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index dbcea27..89c2a96 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -345,3 +345,32 @@
     assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
     panic!("test succeeded")
 }
+
+#[test]
+fn cell_allows_array_cycle() {
+    use core::cell::Cell;
+
+    #[derive(Debug)]
+    struct B<'a> {
+        a: [Cell<Option<&'a B<'a>>>; 2],
+    }
+
+    impl<'a> B<'a> {
+        fn new() -> B<'a> {
+            B { a: [Cell::new(None), Cell::new(None)] }
+        }
+    }
+
+    let b1 = B::new();
+    let b2 = B::new();
+    let b3 = B::new();
+
+    b1.a[0].set(Some(&b2));
+    b1.a[1].set(Some(&b3));
+
+    b2.a[0].set(Some(&b2));
+    b2.a[1].set(Some(&b3));
+
+    b3.a[0].set(Some(&b1));
+    b3.a[1].set(Some(&b2));
+}
diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs
index 801b60b..40be01f 100644
--- a/library/core/tests/cell.rs
+++ b/library/core/tests/cell.rs
@@ -304,6 +304,53 @@
 }
 
 #[test]
+fn cell_exterior() {
+    #[derive(Copy, Clone)]
+    #[allow(dead_code)]
+    struct Point {
+        x: isize,
+        y: isize,
+        z: isize,
+    }
+
+    fn f(p: &Cell<Point>) {
+        assert_eq!(p.get().z, 12);
+        p.set(Point { x: 10, y: 11, z: 13 });
+        assert_eq!(p.get().z, 13);
+    }
+
+    let a = Point { x: 10, y: 11, z: 12 };
+    let b = &Cell::new(a);
+    assert_eq!(b.get().z, 12);
+    f(b);
+    assert_eq!(a.z, 12);
+    assert_eq!(b.get().z, 13);
+}
+
+#[test]
+fn cell_does_not_clone() {
+    #[derive(Copy)]
+    #[allow(dead_code)]
+    struct Foo {
+        x: isize,
+    }
+
+    impl Clone for Foo {
+        fn clone(&self) -> Foo {
+            // Using Cell in any way should never cause clone() to be
+            // invoked -- after all, that would permit evil user code to
+            // abuse `Cell` and trigger crashes.
+
+            panic!();
+        }
+    }
+
+    let x = Cell::new(Foo { x: 22 });
+    let _y = x.get();
+    let _z = x.clone();
+}
+
+#[test]
 fn refcell_default() {
     let cell: RefCell<u64> = Default::default();
     assert_eq!(0, *cell.borrow());
@@ -367,3 +414,11 @@
     let _b = x.borrow();
     x.replace(1);
 }
+
+#[test]
+fn refcell_format() {
+    let name = RefCell::new("rust");
+    let what = RefCell::new("rocks");
+    let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow());
+    assert_eq!(msg, "rust rocks".to_string());
+}
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 0eb9af3..75ca897 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -4,6 +4,43 @@
 use core::convert::TryFrom;
 use core::iter::*;
 
+/// An iterator wrapper that panics whenever `next` or `next_back` is called
+/// after `None` has been returned.
+struct Unfuse<I> {
+    iter: I,
+    exhausted: bool,
+}
+
+fn unfuse<I: IntoIterator>(iter: I) -> Unfuse<I::IntoIter> {
+    Unfuse { iter: iter.into_iter(), exhausted: false }
+}
+
+impl<I> Iterator for Unfuse<I>
+where
+    I: Iterator,
+{
+    type Item = I::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        assert!(!self.exhausted);
+        let next = self.iter.next();
+        self.exhausted = next.is_none();
+        next
+    }
+}
+
+impl<I> DoubleEndedIterator for Unfuse<I>
+where
+    I: DoubleEndedIterator,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        assert!(!self.exhausted);
+        let next = self.iter.next_back();
+        self.exhausted = next.is_none();
+        next
+    }
+}
+
 #[test]
 fn test_lt() {
     let empty: [isize; 0] = [];
@@ -143,6 +180,72 @@
 }
 
 #[test]
+fn test_iterator_chain_advance_by() {
+    fn test_chain(xs: &[i32], ys: &[i32]) {
+        let len = xs.len() + ys.len();
+
+        for i in 0..xs.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_by(i).unwrap();
+            assert_eq!(iter.next(), Some(&xs[i]));
+            assert_eq!(iter.advance_by(100), Err(len - i - 1));
+        }
+
+        for i in 0..ys.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_by(xs.len() + i).unwrap();
+            assert_eq!(iter.next(), Some(&ys[i]));
+            assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
+        }
+
+        let mut iter = xs.iter().chain(ys);
+        iter.advance_by(len).unwrap();
+        assert_eq!(iter.next(), None);
+
+        let mut iter = xs.iter().chain(ys);
+        assert_eq!(iter.advance_by(len + 1), Err(len));
+    }
+
+    test_chain(&[], &[]);
+    test_chain(&[], &[0, 1, 2, 3, 4, 5]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
+}
+
+#[test]
+fn test_iterator_chain_advance_back_by() {
+    fn test_chain(xs: &[i32], ys: &[i32]) {
+        let len = xs.len() + ys.len();
+
+        for i in 0..ys.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_back_by(i).unwrap();
+            assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
+            assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
+        }
+
+        for i in 0..xs.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_back_by(ys.len() + i).unwrap();
+            assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
+            assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
+        }
+
+        let mut iter = xs.iter().chain(ys);
+        iter.advance_back_by(len).unwrap();
+        assert_eq!(iter.next_back(), None);
+
+        let mut iter = xs.iter().chain(ys);
+        assert_eq!(iter.advance_back_by(len + 1), Err(len));
+    }
+
+    test_chain(&[], &[]);
+    test_chain(&[], &[0, 1, 2, 3, 4, 5]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
+}
+
+#[test]
 fn test_iterator_chain_nth() {
     let xs = [0, 1, 2, 3, 4, 5];
     let ys = [30, 40, 50, 60];
@@ -376,6 +479,103 @@
     assert_eq!(b, vec![200, 300, 400]);
 }
 
+#[derive(Debug)]
+struct CountClone(Cell<i32>);
+
+fn count_clone() -> CountClone {
+    CountClone(Cell::new(0))
+}
+
+impl PartialEq<i32> for CountClone {
+    fn eq(&self, rhs: &i32) -> bool {
+        self.0.get() == *rhs
+    }
+}
+
+impl Clone for CountClone {
+    fn clone(&self) -> Self {
+        let ret = CountClone(self.0.clone());
+        let n = self.0.get();
+        self.0.set(n + 1);
+        ret
+    }
+}
+
+#[test]
+fn test_zip_cloned_sideffectful() {
+    let xs = [count_clone(), count_clone(), count_clone(), count_clone()];
+    let ys = [count_clone(), count_clone()];
+
+    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 0][..]);
+    assert_eq!(&ys, &[1, 1][..]);
+
+    let xs = [count_clone(), count_clone()];
+    let ys = [count_clone(), count_clone(), count_clone(), count_clone()];
+
+    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+    assert_eq!(&xs, &[1, 1][..]);
+    assert_eq!(&ys, &[1, 1, 0, 0][..]);
+}
+
+#[test]
+fn test_zip_map_sideffectful() {
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+    assert_eq!(&ys, &[1, 1, 1, 1]);
+
+    let mut xs = [0; 4];
+    let mut ys = [0; 6];
+
+    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 1]);
+    assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
+}
+
+#[test]
+fn test_zip_map_rev_sideffectful() {
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    {
+        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+        it.next_back();
+    }
+    assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
+    assert_eq!(&ys, &[0, 0, 0, 1]);
+
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    {
+        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+        (&mut it).take(5).count();
+        it.next_back();
+    }
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
+    assert_eq!(&ys, &[1, 1, 1, 1]);
+}
+
+#[test]
+fn test_zip_nested_sideffectful() {
+    let mut xs = [0; 6];
+    let ys = [0; 4];
+
+    {
+        // test that it has the side effect nested inside enumerate
+        let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
+        it.count();
+    }
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+}
+
 #[test]
 fn test_zip_nth_back_side_effects_exhausted() {
     let mut a = Vec::new();
@@ -1474,6 +1674,66 @@
 }
 
 #[test]
+fn test_iterator_advance_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter();
+        assert_eq!(iter.advance_by(i), Ok(()));
+        assert_eq!(iter.next().unwrap(), &v[i]);
+        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().advance_by(v.len()), Ok(()));
+    assert_eq!(v.iter().advance_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_advance_back_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter();
+        assert_eq!(iter.advance_back_by(i), Ok(()));
+        assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
+        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
+    assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_rev_advance_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter().rev();
+        assert_eq!(iter.advance_by(i), Ok(()));
+        assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
+        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
+    assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_rev_advance_back_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter().rev();
+        assert_eq!(iter.advance_back_by(i), Ok(()));
+        assert_eq!(iter.next_back().unwrap(), &v[i]);
+        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
+    assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
+}
+
+#[test]
 fn test_iterator_last() {
     let v: &[_] = &[0, 1, 2, 3, 4];
     assert_eq!(v.iter().last().unwrap(), &4);
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 8d86349..0c4ce86 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -41,6 +41,7 @@
 #![feature(slice_partition_dedup)]
 #![feature(int_error_matching)]
 #![feature(array_value_iter)]
+#![feature(iter_advance_by)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_is_partitioned)]
 #![feature(iter_order_by)]
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 27e6760..fcb0d60 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -204,8 +204,8 @@
 
             #[test]
             fn test_from_str() {
-                fn from_str<T: ::std::str::FromStr>(t: &str) -> Option<T> {
-                    ::std::str::FromStr::from_str(t).ok()
+                fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> {
+                    std::str::FromStr::from_str(t).ok()
                 }
                 assert_eq!(from_str::<$T>("0"), Some(0 as $T));
                 assert_eq!(from_str::<$T>("3"), Some(3 as $T));
diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs
new file mode 100644
index 0000000..5d4ecb2
--- /dev/null
+++ b/library/core/tests/num/wrapping.rs
@@ -0,0 +1,76 @@
+use core::num::Wrapping;
+
+macro_rules! wrapping_operation {
+    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
+        assert_eq!($result, $lhs $op $rhs);
+        assert_eq!($result, &$lhs $op $rhs);
+        assert_eq!($result, $lhs $op &$rhs);
+        assert_eq!($result, &$lhs $op &$rhs);
+    };
+    ($result:expr, $op:tt $expr:expr) => {
+        assert_eq!($result, $op $expr);
+        assert_eq!($result, $op &$expr);
+    };
+}
+
+macro_rules! wrapping_assignment {
+    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
+        let mut lhs1 = $lhs;
+        lhs1 $op $rhs;
+        assert_eq!($result, lhs1);
+
+        let mut lhs2 = $lhs;
+        lhs2 $op &$rhs;
+        assert_eq!($result, lhs2);
+    };
+}
+
+macro_rules! wrapping_test {
+    ($type:ty, $min:expr, $max:expr) => {
+        #[test]
+        fn wrapping_$type() {
+            let zero: Wrapping<$type> = Wrapping(0);
+            let one: Wrapping<$type> = Wrapping(1);
+            let min: Wrapping<$type> = Wrapping($min);
+            let max: Wrapping<$type> = Wrapping($max);
+
+            wrapping_operation!(min, max + one);
+            wrapping_assignment!(min, max += one);
+            wrapping_operation!(max, min - one);
+            wrapping_assignment!(max, min -= one);
+            wrapping_operation!(max, max * one);
+            wrapping_assignment!(max, max *= one);
+            wrapping_operation!(max, max / one);
+            wrapping_assignment!(max, max /= one);
+            wrapping_operation!(zero, max % one);
+            wrapping_assignment!(zero, max %= one);
+            wrapping_operation!(zero, zero & max);
+            wrapping_assignment!(zero, zero &= max);
+            wrapping_operation!(max, zero | max);
+            wrapping_assignment!(max, zero |= max);
+            wrapping_operation!(zero, max ^ max);
+            wrapping_assignment!(zero, max ^= max);
+            wrapping_operation!(zero, zero << 1usize);
+            wrapping_assignment!(zero, zero <<= 1usize);
+            wrapping_operation!(zero, zero >> 1usize);
+            wrapping_assignment!(zero, zero >>= 1usize);
+            wrapping_operation!(zero, -zero);
+            wrapping_operation!(max, !min);
+        }
+    };
+}
+
+wrapping_test!(i8, i8::MIN, i8::MAX);
+wrapping_test!(i16, i16::MIN, i16::MAX);
+wrapping_test!(i32, i32::MIN, i32::MAX);
+wrapping_test!(i64, i64::MIN, i64::MAX);
+#[cfg(not(target_os = "emscripten"))]
+wrapping_test!(i128, i128::MIN, i128::MAX);
+wrapping_test!(isize, isize::MIN, isize::MAX);
+wrapping_test!(u8, u8::MIN, u8::MAX);
+wrapping_test!(u16, u16::MIN, u16::MAX);
+wrapping_test!(u32, u32::MIN, u32::MAX);
+wrapping_test!(u64, u64::MIN, u64::MAX);
+#[cfg(not(target_os = "emscripten"))]
+wrapping_test!(u128, u128::MIN, u128::MAX);
+wrapping_test!(usize, usize::MIN, usize::MAX);
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index 9e86e07..ae814ef 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -1,3 +1,4 @@
+use core::cell::Cell;
 use core::clone::Clone;
 use core::mem;
 use core::ops::DerefMut;
@@ -372,3 +373,32 @@
     const IS_NONE: bool = OPTION.is_none();
     assert!(!IS_NONE);
 }
+
+#[test]
+fn test_unwrap_drop() {
+    struct Dtor<'a> {
+        x: &'a Cell<isize>,
+    }
+
+    impl<'a> std::ops::Drop for Dtor<'a> {
+        fn drop(&mut self) {
+            self.x.set(self.x.get() - 1);
+        }
+    }
+
+    fn unwrap<T>(o: Option<T>) -> T {
+        match o {
+            Some(v) => v,
+            None => panic!(),
+        }
+    }
+
+    let x = &Cell::new(1);
+
+    {
+        let b = Some(Dtor { x });
+        let _c = unwrap(b);
+    }
+
+    assert_eq!(x.get(), 0);
+}
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 9556d43..ac5c935 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1,3 +1,4 @@
+use core::cell::Cell;
 use core::result::Result::{Err, Ok};
 
 #[test]
@@ -1570,7 +1571,7 @@
 #[test]
 #[cfg(not(target_arch = "wasm32"))]
 #[cfg_attr(miri, ignore)] // Miri is too slow
-fn partition_at_index() {
+fn select_nth_unstable() {
     use core::cmp::Ordering::{Equal, Greater, Less};
     use rand::rngs::StdRng;
     use rand::seq::SliceRandom;
@@ -1596,7 +1597,7 @@
                 // Sort in default order.
                 for pivot in 0..len {
                     let mut v = orig.clone();
-                    v.partition_at_index(pivot);
+                    v.select_nth_unstable(pivot);
 
                     assert_eq!(v_sorted[pivot], v[pivot]);
                     for i in 0..pivot {
@@ -1609,7 +1610,7 @@
                 // Sort in ascending order.
                 for pivot in 0..len {
                     let mut v = orig.clone();
-                    let (left, pivot, right) = v.partition_at_index_by(pivot, |a, b| a.cmp(b));
+                    let (left, pivot, right) = v.select_nth_unstable_by(pivot, |a, b| a.cmp(b));
 
                     assert_eq!(left.len() + right.len(), len - 1);
 
@@ -1632,7 +1633,7 @@
 
                 for pivot in 0..len {
                     let mut v = orig.clone();
-                    v.partition_at_index_by(pivot, sort_descending_comparator);
+                    v.select_nth_unstable_by(pivot, sort_descending_comparator);
 
                     assert_eq!(v_sorted_descending[pivot], v[pivot]);
                     for i in 0..pivot {
@@ -1653,7 +1654,7 @@
     }
 
     for pivot in 0..v.len() {
-        v.partition_at_index_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
+        v.select_nth_unstable_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
         v.sort();
         for i in 0..v.len() {
             assert_eq!(v[i], i as i32);
@@ -1661,28 +1662,28 @@
     }
 
     // Should not panic.
-    [(); 10].partition_at_index(0);
-    [(); 10].partition_at_index(5);
-    [(); 10].partition_at_index(9);
-    [(); 100].partition_at_index(0);
-    [(); 100].partition_at_index(50);
-    [(); 100].partition_at_index(99);
+    [(); 10].select_nth_unstable(0);
+    [(); 10].select_nth_unstable(5);
+    [(); 10].select_nth_unstable(9);
+    [(); 100].select_nth_unstable(0);
+    [(); 100].select_nth_unstable(50);
+    [(); 100].select_nth_unstable(99);
 
     let mut v = [0xDEADBEEFu64];
-    v.partition_at_index(0);
+    v.select_nth_unstable(0);
     assert!(v == [0xDEADBEEF]);
 }
 
 #[test]
 #[should_panic(expected = "index 0 greater than length of slice")]
-fn partition_at_index_zero_length() {
-    [0i32; 0].partition_at_index(0);
+fn select_nth_unstable_zero_length() {
+    [0i32; 0].select_nth_unstable(0);
 }
 
 #[test]
 #[should_panic(expected = "index 20 greater than length of slice")]
-fn partition_at_index_past_length() {
-    [0i32; 10].partition_at_index(20);
+fn select_nth_unstable_past_length() {
+    [0i32; 10].select_nth_unstable(20);
 }
 
 pub mod memchr {
@@ -1980,3 +1981,30 @@
     assert!(!["c", "bb", "aaa"].is_sorted());
     assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
 }
+
+#[test]
+fn test_slice_run_destructors() {
+    // Make sure that destructors get run on slice literals
+    struct Foo<'a> {
+        x: &'a Cell<isize>,
+    }
+
+    impl<'a> Drop for Foo<'a> {
+        fn drop(&mut self) {
+            self.x.set(self.x.get() + 1);
+        }
+    }
+
+    fn foo(x: &Cell<isize>) -> Foo<'_> {
+        Foo { x }
+    }
+
+    let x = &Cell::new(0);
+
+    {
+        let l = &[foo(x)];
+        assert_eq!(l[0].x.get(), 0);
+    }
+
+    assert_eq!(x.get(), 1);
+}
diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs
index 1cfd527..6b88bab 100644
--- a/library/panic_unwind/src/gcc.rs
+++ b/library/panic_unwind/src/gcc.rs
@@ -114,7 +114,7 @@
 #[cfg(target_arch = "s390x")]
 const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7
 
-#[cfg(target_arch = "sparc64")]
+#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
 const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1
 
 #[cfg(target_arch = "hexagon")]
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index f81ffd2..139b359 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -21,6 +21,7 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
 #![feature(extern_types)]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 01babef..47b59d4 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -16,7 +16,7 @@
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
-libc = { version = "0.2.77", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.79", default-features = false, features = ['rustc-dep-of-std'] }
 compiler_builtins = { version = "0.1.35" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
@@ -24,7 +24,7 @@
 
 # Dependencies of the `backtrace` crate
 addr2line = { version = "0.13.0", optional = true, default-features = false }
-rustc-demangle = { version = "0.1.4", features = ['rustc-dep-of-std'] }
+rustc-demangle = { version = "0.1.18", features = ['rustc-dep-of-std'] }
 miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
 [dependencies.object]
 version = "0.20"
@@ -59,6 +59,7 @@
 panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
 compiler-builtins-c = ["alloc/compiler-builtins-c"]
+compiler-builtins-mem = ["alloc/compiler-builtins-mem"]
 llvm-libunwind = ["unwind/llvm-libunwind"]
 
 # Make panics and failed asserts immediately abort without formatting any message
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index ba15851..dd76006 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -133,7 +133,7 @@
 
 impl System {
     #[inline]
-    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
         match layout.size() {
             0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
             // SAFETY: `layout` is non-zero in size,
@@ -143,7 +143,7 @@
                 } else {
                     GlobalAlloc::alloc(self, layout)
                 };
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 Ok(NonNull::slice_from_raw_parts(ptr, size))
             },
         }
@@ -157,7 +157,7 @@
         old_layout: Layout,
         new_layout: Layout,
         zeroed: bool,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() >= old_layout.size(),
             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
@@ -175,7 +175,7 @@
                 intrinsics::assume(new_size >= old_layout.size());
 
                 let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size);
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 if zeroed {
                     raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
                 }
@@ -202,12 +202,12 @@
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for System {
     #[inline]
-    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         self.alloc_impl(layout, false)
     }
 
     #[inline]
-    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
+    fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         self.alloc_impl(layout, true)
     }
 
@@ -226,7 +226,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: all conditions must be upheld by the caller
         unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
     }
@@ -237,7 +237,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         // SAFETY: all conditions must be upheld by the caller
         unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
     }
@@ -248,7 +248,7 @@
         ptr: NonNull<u8>,
         old_layout: Layout,
         new_layout: Layout,
-    ) -> Result<NonNull<[u8]>, AllocErr> {
+    ) -> Result<NonNull<[u8]>, AllocError> {
         debug_assert!(
             new_layout.size() <= old_layout.size(),
             "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
@@ -267,7 +267,7 @@
                 intrinsics::assume(new_size <= old_layout.size());
 
                 let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size);
-                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
                 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
             },
 
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index cc29e1c..a9d8a4e 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -303,7 +303,8 @@
     // Capture a backtrace which start just before the function addressed by
     // `ip`
     fn create(ip: usize) -> Backtrace {
-        let _lock = lock();
+        // SAFETY: We don't attempt to lock this reentrantly.
+        let _lock = unsafe { lock() };
         let mut frames = Vec::new();
         let mut actual_start = None;
         unsafe {
@@ -408,7 +409,8 @@
         // Use the global backtrace lock to synchronize this as it's a
         // requirement of the `backtrace` crate, and then actually resolve
         // everything.
-        let _lock = lock();
+        // SAFETY: We don't attempt to lock this reentrantly.
+        let _lock = unsafe { lock() };
         for frame in self.frames.iter_mut() {
             let symbols = &mut frame.symbols;
             let frame = match &frame.frame {
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 1bb835e..114707b 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -554,8 +554,8 @@
     /// a.clear();
     /// assert!(a.is_empty());
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn clear(&mut self) {
         self.base.clear();
     }
@@ -746,8 +746,8 @@
     /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
     /// assert_eq!(map.get_key_value(&2), None);
     /// ```
-    #[stable(feature = "map_get_key_value", since = "1.40.0")]
     #[inline]
+    #[stable(feature = "map_get_key_value", since = "1.40.0")]
     pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
     where
         K: Borrow<Q>,
@@ -772,8 +772,8 @@
     /// assert_eq!(map.contains_key(&1), true);
     /// assert_eq!(map.contains_key(&2), false);
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
     where
         K: Borrow<Q>,
@@ -800,8 +800,8 @@
     /// }
     /// assert_eq!(map[&1], "b");
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
     where
         K: Borrow<Q>,
@@ -834,8 +834,8 @@
     /// assert_eq!(map.insert(37, "c"), Some("b"));
     /// assert_eq!(map[&37], "c");
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, k: K, v: V) -> Option<V> {
         self.base.insert(k, v)
     }
@@ -857,8 +857,8 @@
     /// assert_eq!(map.remove(&1), Some("a"));
     /// assert_eq!(map.remove(&1), None);
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
     where
         K: Borrow<Q>,
@@ -886,8 +886,8 @@
     /// assert_eq!(map.remove(&1), None);
     /// # }
     /// ```
-    #[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
     #[inline]
+    #[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
     pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
     where
         K: Borrow<Q>,
@@ -909,8 +909,8 @@
     /// map.retain(|&k, _| k % 2 == 0);
     /// assert_eq!(map.len(), 4);
     /// ```
-    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
     #[inline]
+    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
     pub fn retain<F>(&mut self, f: F)
     where
         F: FnMut(&K, &mut V) -> bool,
@@ -1647,7 +1647,7 @@
         self.base.get()
     }
 
-    /// Converts the OccupiedEntry into a mutable reference to the value in the entry
+    /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
     /// with a lifetime bound to the map itself.
     #[inline]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
@@ -1676,7 +1676,7 @@
         self.base.get_key_value_mut()
     }
 
-    /// Converts the OccupiedEntry into a mutable reference to the key and value in the entry
+    /// Converts the `OccupiedEntry` into a mutable reference to the key and value in the entry
     /// with a lifetime bound to the map itself.
     #[inline]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
@@ -1714,7 +1714,7 @@
 }
 
 impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
-    /// Sets the value of the entry with the VacantEntry's key,
+    /// Sets the value of the entry with the `VacantEntry`'s key,
     /// and returns a mutable reference to it.
     #[inline]
     #[unstable(feature = "hash_raw_entry", issue = "56167")]
@@ -2042,13 +2042,9 @@
 impl<K, V> FusedIterator for ValuesMut<'_, K, V> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
-impl<K, V> fmt::Debug for ValuesMut<'_, K, V>
-where
-    K: fmt::Debug,
-    V: fmt::Debug,
-{
+impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.inner.iter()).finish()
+        f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
     }
 }
 
@@ -2076,7 +2072,7 @@
 impl<K, V> FusedIterator for IntoKeys<K, V> {}
 
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-impl<K: Debug, V: Debug> fmt::Debug for IntoKeys<K, V> {
+impl<K: Debug, V> fmt::Debug for IntoKeys<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
     }
@@ -2106,7 +2102,7 @@
 impl<K, V> FusedIterator for IntoValues<K, V> {}
 
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-impl<K: Debug, V: Debug> fmt::Debug for IntoValues<K, V> {
+impl<K, V: Debug> fmt::Debug for IntoValues<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
     }
@@ -2177,7 +2173,6 @@
 }
 
 impl<'a, K, V> Entry<'a, K, V> {
-    #[stable(feature = "rust1", since = "1.0.0")]
     /// Ensures a value is in the entry by inserting the default if empty, and returns
     /// a mutable reference to the value in the entry.
     ///
@@ -2195,6 +2190,7 @@
     /// assert_eq!(map["poneyland"], 6);
     /// ```
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn or_insert(self, default: V) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2202,7 +2198,6 @@
         }
     }
 
-    #[stable(feature = "rust1", since = "1.0.0")]
     /// Ensures a value is in the entry by inserting the result of the default function if empty,
     /// and returns a mutable reference to the value in the entry.
     ///
@@ -2219,6 +2214,7 @@
     /// assert_eq!(map["poneyland"], "hoho".to_string());
     /// ```
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2226,7 +2222,6 @@
         }
     }
 
-    #[unstable(feature = "or_insert_with_key", issue = "71024")]
     /// Ensures a value is in the entry by inserting, if empty, the result of the default function,
     /// which takes the key as its argument, and returns a mutable reference to the value in the
     /// entry.
@@ -2244,6 +2239,7 @@
     /// assert_eq!(map["poneyland"], 9);
     /// ```
     #[inline]
+    #[unstable(feature = "or_insert_with_key", issue = "71024")]
     pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2308,7 +2304,7 @@
         }
     }
 
-    /// Sets the value of the entry, and returns an OccupiedEntry.
+    /// Sets the value of the entry, and returns an `OccupiedEntry`.
     ///
     /// # Examples
     ///
@@ -2335,7 +2331,6 @@
 }
 
 impl<'a, K, V: Default> Entry<'a, K, V> {
-    #[stable(feature = "entry_or_default", since = "1.28.0")]
     /// Ensures a value is in the entry by inserting the default value if empty,
     /// and returns a mutable reference to the value in the entry.
     ///
@@ -2352,6 +2347,7 @@
     /// # }
     /// ```
     #[inline]
+    #[stable(feature = "entry_or_default", since = "1.28.0")]
     pub fn or_default(self) -> &'a mut V {
         match self {
             Occupied(entry) => entry.into_mut(),
@@ -2456,7 +2452,7 @@
         self.base.get_mut()
     }
 
-    /// Converts the OccupiedEntry into a mutable reference to the value in the entry
+    /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
     /// with a lifetime bound to the map itself.
     ///
     /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
@@ -2628,7 +2624,7 @@
         self.base.into_key()
     }
 
-    /// Sets the value of the entry with the VacantEntry's key,
+    /// Sets the value of the entry with the `VacantEntry`'s key,
     /// and returns a mutable reference to it.
     ///
     /// # Examples
@@ -2650,8 +2646,8 @@
         self.base.insert(value)
     }
 
-    /// Sets the value of the entry with the VacantEntry's key,
-    /// and returns an OccupiedEntry.
+    /// Sets the value of the entry with the `VacantEntry`'s key,
+    /// and returns an `OccupiedEntry`.
     ///
     /// # Examples
     ///
@@ -2836,11 +2832,10 @@
 
 #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
 impl Default for DefaultHasher {
-    // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link
-    // resolution failure when re-exporting libstd items. When #56922 fixed,
-    // link `new` to [DefaultHasher::new] again.
-    /// Creates a new `DefaultHasher` using `new`.
+    /// Creates a new `DefaultHasher` using [`new`].
     /// See its documentation for more.
+    ///
+    /// [`new`]: DefaultHasher::new
     fn default() -> DefaultHasher {
         DefaultHasher::new()
     }
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index ee25311..5771ca7 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -19,7 +19,7 @@
 use core::array;
 use core::convert::Infallible;
 
-use crate::alloc::{AllocErr, LayoutErr};
+use crate::alloc::{AllocError, LayoutErr};
 use crate::any::TypeId;
 use crate::backtrace::Backtrace;
 use crate::borrow::Cow;
@@ -387,7 +387,7 @@
     reason = "the precise API and guarantees it provides may be tweaked.",
     issue = "32838"
 )]
-impl Error for AllocErr {}
+impl Error for AllocError {}
 
 #[stable(feature = "alloc_layout", since = "1.28.0")]
 impl Error for LayoutErr {}
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 1302173..6df4eb9 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -1383,7 +1383,8 @@
     /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
     /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
     ///
-    /// [`str`]: prim@str
+    /// [`str`]: primitive@str
+    /// [`&str`]: primitive@str
     /// [`Borrowed`]: Cow::Borrowed
     /// [`Owned`]: Cow::Owned
     /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 2663f68..7e7a28b 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -69,7 +69,7 @@
 /// [`&OsStr`]: OsStr
 /// [`&str`]: str
 /// [`CStr`]: crate::ffi::CStr
-/// [conversions]: index.html#conversions
+/// [conversions]: super#conversions
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
@@ -88,7 +88,7 @@
 /// the traits which `OsStr` implements for [conversions] from/to native representations.
 ///
 /// [`&str`]: str
-/// [conversions]: index.html#conversions
+/// [conversions]: super#conversions
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME:
 // `OsStr::from_inner` current implementation relies
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 65a2907..38fd470 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -73,10 +73,9 @@
     let link = tmpdir.join("some_hopefully_unique_link_name");
 
     match symlink_file(r"nonexisting_target", link) {
-        Ok(_) => true,
         // ERROR_PRIVILEGE_NOT_HELD = 1314
         Err(ref err) if err.raw_os_error() == Some(1314) => false,
-        Err(_) => true,
+        Ok(_) | Err(_) => true,
     }
 }
 
diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs
deleted file mode 100644
index 97c4b87..0000000
--- a/library/std/src/io/buffered.rs
+++ /dev/null
@@ -1,1438 +0,0 @@
-//! Buffering wrappers for I/O traits
-
-#[cfg(test)]
-mod tests;
-
-use crate::io::prelude::*;
-
-use crate::cmp;
-use crate::error;
-use crate::fmt;
-use crate::io::{
-    self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom, DEFAULT_BUF_SIZE,
-};
-use crate::memchr;
-
-/// The `BufReader<R>` struct adds buffering to any reader.
-///
-/// It can be excessively inefficient to work directly with a [`Read`] instance.
-/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
-/// results in a system call. A `BufReader<R>` performs large, infrequent reads on
-/// the underlying [`Read`] and maintains an in-memory buffer of the results.
-///
-/// `BufReader<R>` can improve the speed of programs that make *small* and
-/// *repeated* read calls to the same file or network socket. It does not
-/// help when reading very large amounts at once, or reading just one or a few
-/// times. It also provides no advantage when reading from a source that is
-/// already in memory, like a [`Vec`]`<u8>`.
-///
-/// When the `BufReader<R>` is dropped, the contents of its buffer will be
-/// discarded. Creating multiple instances of a `BufReader<R>` on the same
-/// stream can cause data loss. Reading from the underlying reader after
-/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause
-/// data loss.
-///
-/// [`TcpStream::read`]: Read::read
-/// [`TcpStream`]: crate::net::TcpStream
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::io::BufReader;
-/// use std::fs::File;
-///
-/// fn main() -> std::io::Result<()> {
-///     let f = File::open("log.txt")?;
-///     let mut reader = BufReader::new(f);
-///
-///     let mut line = String::new();
-///     let len = reader.read_line(&mut line)?;
-///     println!("First line is {} bytes long", len);
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufReader<R> {
-    inner: R,
-    buf: Box<[u8]>,
-    pos: usize,
-    cap: usize,
-}
-
-impl<R: Read> BufReader<R> {
-    /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB,
-    /// but may change in the future.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let reader = BufReader::new(f);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new(inner: R) -> BufReader<R> {
-        BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
-    }
-
-    /// Creates a new `BufReader<R>` with the specified buffer capacity.
-    ///
-    /// # Examples
-    ///
-    /// Creating a buffer with ten bytes of capacity:
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let reader = BufReader::with_capacity(10, f);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
-        unsafe {
-            let mut buffer = Vec::with_capacity(capacity);
-            buffer.set_len(capacity);
-            inner.initializer().initialize(&mut buffer);
-            BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 }
-        }
-    }
-}
-
-impl<R> BufReader<R> {
-    /// Gets a reference to the underlying reader.
-    ///
-    /// It is inadvisable to directly read from the underlying reader.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f1 = File::open("log.txt")?;
-    ///     let reader = BufReader::new(f1);
-    ///
-    ///     let f2 = reader.get_ref();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &R {
-        &self.inner
-    }
-
-    /// Gets a mutable reference to the underlying reader.
-    ///
-    /// It is inadvisable to directly read from the underlying reader.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f1 = File::open("log.txt")?;
-    ///     let mut reader = BufReader::new(f1);
-    ///
-    ///     let f2 = reader.get_mut();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut R {
-        &mut self.inner
-    }
-
-    /// Returns a reference to the internally buffered data.
-    ///
-    /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty.
-    ///
-    /// [`fill_buf`]: BufRead::fill_buf
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::{BufReader, BufRead};
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let mut reader = BufReader::new(f);
-    ///     assert!(reader.buffer().is_empty());
-    ///
-    ///     if reader.fill_buf()?.len() > 0 {
-    ///         assert!(!reader.buffer().is_empty());
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
-    pub fn buffer(&self) -> &[u8] {
-        &self.buf[self.pos..self.cap]
-    }
-
-    /// Returns the number of bytes the internal buffer can hold at once.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::{BufReader, BufRead};
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let mut reader = BufReader::new(f);
-    ///
-    ///     let capacity = reader.capacity();
-    ///     let buffer = reader.fill_buf()?;
-    ///     assert!(buffer.len() <= capacity);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
-    pub fn capacity(&self) -> usize {
-        self.buf.len()
-    }
-
-    /// Unwraps this `BufReader<R>`, returning the underlying reader.
-    ///
-    /// Note that any leftover data in the internal buffer is lost. Therefore,
-    /// a following read from the underlying reader may lead to data loss.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f1 = File::open("log.txt")?;
-    ///     let reader = BufReader::new(f1);
-    ///
-    ///     let f2 = reader.into_inner();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> R {
-        self.inner
-    }
-
-    /// Invalidates all data in the internal buffer.
-    #[inline]
-    fn discard_buffer(&mut self) {
-        self.pos = 0;
-        self.cap = 0;
-    }
-}
-
-impl<R: Seek> BufReader<R> {
-    /// Seeks relative to the current position. If the new position lies within the buffer,
-    /// the buffer will not be flushed, allowing for more efficient seeks.
-    /// This method does not return the location of the underlying reader, so the caller
-    /// must track this information themselves if it is required.
-    #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
-    pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
-        let pos = self.pos as u64;
-        if offset < 0 {
-            if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
-                self.pos = new_pos as usize;
-                return Ok(());
-            }
-        } else {
-            if let Some(new_pos) = pos.checked_add(offset as u64) {
-                if new_pos <= self.cap as u64 {
-                    self.pos = new_pos as usize;
-                    return Ok(());
-                }
-            }
-        }
-        self.seek(SeekFrom::Current(offset)).map(drop)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> Read for BufReader<R> {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        // If we don't have any buffered data and we're doing a massive read
-        // (larger than our internal buffer), bypass our internal buffer
-        // entirely.
-        if self.pos == self.cap && buf.len() >= self.buf.len() {
-            self.discard_buffer();
-            return self.inner.read(buf);
-        }
-        let nread = {
-            let mut rem = self.fill_buf()?;
-            rem.read(buf)?
-        };
-        self.consume(nread);
-        Ok(nread)
-    }
-
-    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
-        if self.pos == self.cap && total_len >= self.buf.len() {
-            self.discard_buffer();
-            return self.inner.read_vectored(bufs);
-        }
-        let nread = {
-            let mut rem = self.fill_buf()?;
-            rem.read_vectored(bufs)?
-        };
-        self.consume(nread);
-        Ok(nread)
-    }
-
-    fn is_read_vectored(&self) -> bool {
-        self.inner.is_read_vectored()
-    }
-
-    // we can't skip unconditionally because of the large buffer case in read.
-    unsafe fn initializer(&self) -> Initializer {
-        self.inner.initializer()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> BufRead for BufReader<R> {
-    fn fill_buf(&mut self) -> io::Result<&[u8]> {
-        // If we've reached the end of our internal buffer then we need to fetch
-        // some more data from the underlying reader.
-        // Branch using `>=` instead of the more correct `==`
-        // to tell the compiler that the pos..cap slice is always valid.
-        if self.pos >= self.cap {
-            debug_assert!(self.pos == self.cap);
-            self.cap = self.inner.read(&mut self.buf)?;
-            self.pos = 0;
-        }
-        Ok(&self.buf[self.pos..self.cap])
-    }
-
-    fn consume(&mut self, amt: usize) {
-        self.pos = cmp::min(self.pos + amt, self.cap);
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R> fmt::Debug for BufReader<R>
-where
-    R: fmt::Debug,
-{
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_struct("BufReader")
-            .field("reader", &self.inner)
-            .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
-            .finish()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Seek> Seek for BufReader<R> {
-    /// Seek to an offset, in bytes, in the underlying reader.
-    ///
-    /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
-    /// position the underlying reader would be at if the `BufReader<R>` had no
-    /// internal buffer.
-    ///
-    /// Seeking always discards the internal buffer, even if the seek position
-    /// would otherwise fall within it. This guarantees that calling
-    /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
-    /// at the same position.
-    ///
-    /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
-    ///
-    /// See [`std::io::Seek`] for more details.
-    ///
-    /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
-    /// where `n` minus the internal buffer length overflows an `i64`, two
-    /// seeks will be performed instead of one. If the second seek returns
-    /// [`Err`], the underlying reader will be left at the same position it would
-    /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
-    ///
-    /// [`std::io::Seek`]: Seek
-    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
-        let result: u64;
-        if let SeekFrom::Current(n) = pos {
-            let remainder = (self.cap - self.pos) as i64;
-            // it should be safe to assume that remainder fits within an i64 as the alternative
-            // means we managed to allocate 8 exbibytes and that's absurd.
-            // But it's not out of the realm of possibility for some weird underlying reader to
-            // support seeking by i64::MIN so we need to handle underflow when subtracting
-            // remainder.
-            if let Some(offset) = n.checked_sub(remainder) {
-                result = self.inner.seek(SeekFrom::Current(offset))?;
-            } else {
-                // seek backwards by our remainder, and then by the offset
-                self.inner.seek(SeekFrom::Current(-remainder))?;
-                self.discard_buffer();
-                result = self.inner.seek(SeekFrom::Current(n))?;
-            }
-        } else {
-            // Seeking with Start/End doesn't care about our buffer length.
-            result = self.inner.seek(pos)?;
-        }
-        self.discard_buffer();
-        Ok(result)
-    }
-
-    /// Returns the current seek position from the start of the stream.
-    ///
-    /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
-    /// but does not flush the internal buffer. Due to this optimization the
-    /// function does not guarantee that calling `.into_inner()` immediately
-    /// afterwards will yield the underlying reader at the same position. Use
-    /// [`BufReader::seek`] instead if you require that guarantee.
-    ///
-    /// # Panics
-    ///
-    /// This function will panic if the position of the inner reader is smaller
-    /// than the amount of buffered data. That can happen if the inner reader
-    /// has an incorrect implementation of [`Seek::stream_position`], or if the
-    /// position has gone out of sync due to calling [`Seek::seek`] directly on
-    /// the underlying reader.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// #![feature(seek_convenience)]
-    /// use std::{
-    ///     io::{self, BufRead, BufReader, Seek},
-    ///     fs::File,
-    /// };
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let mut f = BufReader::new(File::open("foo.txt")?);
-    ///
-    ///     let before = f.stream_position()?;
-    ///     f.read_line(&mut String::new())?;
-    ///     let after = f.stream_position()?;
-    ///
-    ///     println!("The first line was {} bytes long", after - before);
-    ///     Ok(())
-    /// }
-    /// ```
-    fn stream_position(&mut self) -> io::Result<u64> {
-        let remainder = (self.cap - self.pos) as u64;
-        self.inner.stream_position().map(|pos| {
-            pos.checked_sub(remainder).expect(
-                "overflow when subtracting remaining buffer size from inner stream position",
-            )
-        })
-    }
-}
-
-/// Wraps a writer and buffers its output.
-///
-/// It can be excessively inefficient to work directly with something that
-/// implements [`Write`]. For example, every call to
-/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
-/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying
-/// writer in large, infrequent batches.
-///
-/// `BufWriter<W>` can improve the speed of programs that make *small* and
-/// *repeated* write calls to the same file or network socket. It does not
-/// help when writing very large amounts at once, or writing just one or a few
-/// times. It also provides no advantage when writing to a destination that is
-/// in memory, like a [`Vec`]<u8>`.
-///
-/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
-/// dropping will attempt to flush the contents of the buffer, any errors
-/// that happen in the process of dropping will be ignored. Calling [`flush`]
-/// ensures that the buffer is empty and thus dropping will not even attempt
-/// file operations.
-///
-/// # Examples
-///
-/// Let's write the numbers one through ten to a [`TcpStream`]:
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::net::TcpStream;
-///
-/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
-///
-/// for i in 0..10 {
-///     stream.write(&[i+1]).unwrap();
-/// }
-/// ```
-///
-/// Because we're not buffering, we write each one in turn, incurring the
-/// overhead of a system call per byte written. We can fix this with a
-/// `BufWriter<W>`:
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::io::BufWriter;
-/// use std::net::TcpStream;
-///
-/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-///
-/// for i in 0..10 {
-///     stream.write(&[i+1]).unwrap();
-/// }
-/// stream.flush().unwrap();
-/// ```
-///
-/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped
-/// together by the buffer and will all be written out in one system call when
-/// the `stream` is flushed.
-///
-/// [`TcpStream::write`]: Write::write
-/// [`TcpStream`]: crate::net::TcpStream
-/// [`flush`]: Write::flush
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufWriter<W: Write> {
-    inner: Option<W>,
-    buf: Vec<u8>,
-    // #30888: If the inner writer panics in a call to write, we don't want to
-    // write the buffered data a second time in BufWriter's destructor. This
-    // flag tells the Drop impl if it should skip the flush.
-    panicked: bool,
-}
-
-/// An error returned by [`BufWriter::into_inner`] which combines an error that
-/// happened while writing out the buffer, and the buffered writer object
-/// which may be used to recover from the condition.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::io::BufWriter;
-/// use std::net::TcpStream;
-///
-/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-///
-/// // do stuff with the stream
-///
-/// // we want to get our `TcpStream` back, so let's try:
-///
-/// let stream = match stream.into_inner() {
-///     Ok(s) => s,
-///     Err(e) => {
-///         // Here, e is an IntoInnerError
-///         panic!("An error occurred");
-///     }
-/// };
-/// ```
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IntoInnerError<W>(W, Error);
-
-impl<W: Write> BufWriter<W> {
-    /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB,
-    /// but may change in the future.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new(inner: W) -> BufWriter<W> {
-        BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
-    }
-
-    /// Creates a new `BufWriter<W>` with the specified buffer capacity.
-    ///
-    /// # Examples
-    ///
-    /// Creating a buffer with a buffer of a hundred bytes.
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
-    /// let mut buffer = BufWriter::with_capacity(100, stream);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> {
-        BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false }
-    }
-
-    /// Send data in our local buffer into the inner writer, looping as
-    /// necessary until either it's all been sent or an error occurs.
-    ///
-    /// Because all the data in the buffer has been reported to our owner as
-    /// "successfully written" (by returning nonzero success values from
-    /// `write`), any 0-length writes from `inner` must be reported as i/o
-    /// errors from this method.
-    fn flush_buf(&mut self) -> io::Result<()> {
-        /// Helper struct to ensure the buffer is updated after all the writes
-        /// are complete. It tracks the number of written bytes and drains them
-        /// all from the front of the buffer when dropped.
-        struct BufGuard<'a> {
-            buffer: &'a mut Vec<u8>,
-            written: usize,
-        }
-
-        impl<'a> BufGuard<'a> {
-            fn new(buffer: &'a mut Vec<u8>) -> Self {
-                Self { buffer, written: 0 }
-            }
-
-            /// The unwritten part of the buffer
-            fn remaining(&self) -> &[u8] {
-                &self.buffer[self.written..]
-            }
-
-            /// Flag some bytes as removed from the front of the buffer
-            fn consume(&mut self, amt: usize) {
-                self.written += amt;
-            }
-
-            /// true if all of the bytes have been written
-            fn done(&self) -> bool {
-                self.written >= self.buffer.len()
-            }
-        }
-
-        impl Drop for BufGuard<'_> {
-            fn drop(&mut self) {
-                if self.written > 0 {
-                    self.buffer.drain(..self.written);
-                }
-            }
-        }
-
-        let mut guard = BufGuard::new(&mut self.buf);
-        let inner = self.inner.as_mut().unwrap();
-        while !guard.done() {
-            self.panicked = true;
-            let r = inner.write(guard.remaining());
-            self.panicked = false;
-
-            match r {
-                Ok(0) => {
-                    return Err(Error::new(
-                        ErrorKind::WriteZero,
-                        "failed to write the buffered data",
-                    ));
-                }
-                Ok(n) => guard.consume(n),
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        Ok(())
-    }
-
-    /// Buffer some data without flushing it, regardless of the size of the
-    /// data. Writes as much as possible without exceeding capacity. Returns
-    /// the number of bytes written.
-    fn write_to_buf(&mut self, buf: &[u8]) -> usize {
-        let available = self.buf.capacity() - self.buf.len();
-        let amt_to_buffer = available.min(buf.len());
-        self.buf.extend_from_slice(&buf[..amt_to_buffer]);
-        amt_to_buffer
-    }
-
-    /// Gets a reference to the underlying writer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // we can use reference just like buffer
-    /// let reference = buffer.get_ref();
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &W {
-        self.inner.as_ref().unwrap()
-    }
-
-    /// Gets a mutable reference to the underlying writer.
-    ///
-    /// It is inadvisable to directly write to the underlying writer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // we can use reference just like buffer
-    /// let reference = buffer.get_mut();
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut W {
-        self.inner.as_mut().unwrap()
-    }
-
-    /// Returns a reference to the internally buffered data.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // See how many bytes are currently buffered
-    /// let bytes_buffered = buf_writer.buffer().len();
-    /// ```
-    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
-    pub fn buffer(&self) -> &[u8] {
-        &self.buf
-    }
-
-    /// Returns the number of bytes the internal buffer can hold without flushing.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // Check the capacity of the inner buffer
-    /// let capacity = buf_writer.capacity();
-    /// // Calculate how many bytes can be written without flushing
-    /// let without_flush = capacity - buf_writer.buffer().len();
-    /// ```
-    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
-    pub fn capacity(&self) -> usize {
-        self.buf.capacity()
-    }
-
-    /// Unwraps this `BufWriter<W>`, returning the underlying writer.
-    ///
-    /// The buffer is written out before returning the writer.
-    ///
-    /// # Errors
-    ///
-    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // unwrap the TcpStream and flush the buffer
-    /// let stream = buffer.into_inner().unwrap();
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
-        match self.flush_buf() {
-            Err(e) => Err(IntoInnerError(self, e)),
-            Ok(()) => Ok(self.inner.take().unwrap()),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for BufWriter<W> {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
-            Ok(buf.len())
-        }
-    }
-
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        // Normally, `write_all` just calls `write` in a loop. We can do better
-        // by calling `self.get_mut().write_all()` directly, which avoids
-        // round trips through the buffer in the event of a series of partial
-        // writes in some circumstances.
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write_all(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
-            Ok(())
-        }
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
-        if self.buf.len() + total_len > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if total_len >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write_vectored(bufs);
-            self.panicked = false;
-            r
-        } else {
-            bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
-            Ok(total_len)
-        }
-    }
-
-    fn is_write_vectored(&self) -> bool {
-        self.get_ref().is_write_vectored()
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.flush_buf().and_then(|()| self.get_mut().flush())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for BufWriter<W>
-where
-    W: fmt::Debug,
-{
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_struct("BufWriter")
-            .field("writer", &self.inner.as_ref().unwrap())
-            .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
-            .finish()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write + Seek> Seek for BufWriter<W> {
-    /// Seek to the offset, in bytes, in the underlying writer.
-    ///
-    /// Seeking always writes out the internal buffer before seeking.
-    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
-        self.flush_buf()?;
-        self.get_mut().seek(pos)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Drop for BufWriter<W> {
-    fn drop(&mut self) {
-        if self.inner.is_some() && !self.panicked {
-            // dtors should not panic, so we ignore a failed flush
-            let _r = self.flush_buf();
-        }
-    }
-}
-
-impl<W> IntoInnerError<W> {
-    /// Returns the error which caused the call to [`BufWriter::into_inner()`]
-    /// to fail.
-    ///
-    /// This error was returned when attempting to write the internal buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // do stuff with the stream
-    ///
-    /// // we want to get our `TcpStream` back, so let's try:
-    ///
-    /// let stream = match stream.into_inner() {
-    ///     Ok(s) => s,
-    ///     Err(e) => {
-    ///         // Here, e is an IntoInnerError, let's log the inner error.
-    ///         //
-    ///         // We'll just 'log' to stdout for this example.
-    ///         println!("{}", e.error());
-    ///
-    ///         panic!("An unexpected error occurred.");
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn error(&self) -> &Error {
-        &self.1
-    }
-
-    /// Returns the buffered writer instance which generated the error.
-    ///
-    /// The returned object can be used for error recovery, such as
-    /// re-inspecting the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // do stuff with the stream
-    ///
-    /// // we want to get our `TcpStream` back, so let's try:
-    ///
-    /// let stream = match stream.into_inner() {
-    ///     Ok(s) => s,
-    ///     Err(e) => {
-    ///         // Here, e is an IntoInnerError, let's re-examine the buffer:
-    ///         let buffer = e.into_inner();
-    ///
-    ///         // do stuff to try to recover
-    ///
-    ///         // afterwards, let's just return the stream
-    ///         buffer.into_inner().unwrap()
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> W {
-        self.0
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W> From<IntoInnerError<W>> for Error {
-    fn from(iie: IntoInnerError<W>) -> Error {
-        iie.1
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
-    #[allow(deprecated, deprecated_in_future)]
-    fn description(&self) -> &str {
-        error::Error::description(self.error())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W> fmt::Display for IntoInnerError<W> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.error().fmt(f)
-    }
-}
-
-/// Private helper struct for implementing the line-buffered writing logic.
-/// This shim temporarily wraps a BufWriter, and uses its internals to
-/// implement a line-buffered writer (specifically by using the internal
-/// methods like write_to_buf and flush_buf). In this way, a more
-/// efficient abstraction can be created than one that only had access to
-/// `write` and `flush`, without needlessly duplicating a lot of the
-/// implementation details of BufWriter. This also allows existing
-/// `BufWriters` to be temporarily given line-buffering logic; this is what
-/// enables Stdout to be alternately in line-buffered or block-buffered mode.
-#[derive(Debug)]
-pub(super) struct LineWriterShim<'a, W: Write> {
-    buffer: &'a mut BufWriter<W>,
-}
-
-impl<'a, W: Write> LineWriterShim<'a, W> {
-    pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
-        Self { buffer }
-    }
-
-    /// Get a mutable reference to the inner writer (that is, the writer
-    /// wrapped by the BufWriter). Be careful with this writer, as writes to
-    /// it will bypass the buffer.
-    fn inner_mut(&mut self) -> &mut W {
-        self.buffer.get_mut()
-    }
-
-    /// Get the content currently buffered in self.buffer
-    fn buffered(&self) -> &[u8] {
-        self.buffer.buffer()
-    }
-
-    /// Flush the buffer iff the last byte is a newline (indicating that an
-    /// earlier write only succeeded partially, and we want to retry flushing
-    /// the buffered line before continuing with a subsequent write)
-    fn flush_if_completed_line(&mut self) -> io::Result<()> {
-        match self.buffered().last().copied() {
-            Some(b'\n') => self.buffer.flush_buf(),
-            _ => Ok(()),
-        }
-    }
-}
-
-impl<'a, W: Write> Write for LineWriterShim<'a, W> {
-    /// Write some data into this BufReader with line buffering. This means
-    /// that, if any newlines are present in the data, the data up to the last
-    /// newline is sent directly to the underlying writer, and data after it
-    /// is buffered. Returns the number of bytes written.
-    ///
-    /// This function operates on a "best effort basis"; in keeping with the
-    /// convention of `Write::write`, it makes at most one attempt to write
-    /// new data to the underlying writer. If that write only reports a partial
-    /// success, the remaining data will be buffered.
-    ///
-    /// Because this function attempts to send completed lines to the underlying
-    /// writer, it will also flush the existing buffer if it ends with a
-    /// newline, even if the incoming data does not contain any newlines.
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        let newline_idx = match memchr::memrchr(b'\n', buf) {
-            // If there are no new newlines (that is, if this write is less than
-            // one line), just do a regular buffered write (which may flush if
-            // we exceed the inner buffer's size)
-            None => {
-                self.flush_if_completed_line()?;
-                return self.buffer.write(buf);
-            }
-            // Otherwise, arrange for the lines to be written directly to the
-            // inner writer.
-            Some(newline_idx) => newline_idx + 1,
-        };
-
-        // Flush existing content to prepare for our write. We have to do this
-        // before attempting to write `buf` in order to maintain consistency;
-        // if we add `buf` to the buffer then try to flush it all at once,
-        // we're obligated to return Ok(), which would mean suppressing any
-        // errors that occur during flush.
-        self.buffer.flush_buf()?;
-
-        // This is what we're going to try to write directly to the inner
-        // writer. The rest will be buffered, if nothing goes wrong.
-        let lines = &buf[..newline_idx];
-
-        // Write `lines` directly to the inner writer. In keeping with the
-        // `write` convention, make at most one attempt to add new (unbuffered)
-        // data. Because this write doesn't touch the BufWriter state directly,
-        // and the buffer is known to be empty, we don't need to worry about
-        // self.buffer.panicked here.
-        let flushed = self.inner_mut().write(lines)?;
-
-        // If buffer returns Ok(0), propagate that to the caller without
-        // doing additional buffering; otherwise we're just guaranteeing
-        // an "ErrorKind::WriteZero" later.
-        if flushed == 0 {
-            return Ok(0);
-        }
-
-        // Now that the write has succeeded, buffer the rest (or as much of
-        // the rest as possible). If there were any unwritten newlines, we
-        // only buffer out to the last unwritten newline that fits in the
-        // buffer; this helps prevent flushing partial lines on subsequent
-        // calls to LineWriterShim::write.
-
-        // Handle the cases in order of most-common to least-common, under
-        // the presumption that most writes succeed in totality, and that most
-        // writes are smaller than the buffer.
-        // - Is this a partial line (ie, no newlines left in the unwritten tail)
-        // - If not, does the data out to the last unwritten newline fit in
-        //   the buffer?
-        // - If not, scan for the last newline that *does* fit in the buffer
-        let tail = if flushed >= newline_idx {
-            &buf[flushed..]
-        } else if newline_idx - flushed <= self.buffer.capacity() {
-            &buf[flushed..newline_idx]
-        } else {
-            let scan_area = &buf[flushed..];
-            let scan_area = &scan_area[..self.buffer.capacity()];
-            match memchr::memrchr(b'\n', scan_area) {
-                Some(newline_idx) => &scan_area[..newline_idx + 1],
-                None => scan_area,
-            }
-        };
-
-        let buffered = self.buffer.write_to_buf(tail);
-        Ok(flushed + buffered)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.buffer.flush()
-    }
-
-    /// Write some vectored data into this BufReader with line buffering. This
-    /// means that, if any newlines are present in the data, the data up to
-    /// and including the buffer containing the last newline is sent directly
-    /// to the inner writer, and the data after it is buffered. Returns the
-    /// number of bytes written.
-    ///
-    /// This function operates on a "best effort basis"; in keeping with the
-    /// convention of `Write::write`, it makes at most one attempt to write
-    /// new data to the underlying writer.
-    ///
-    /// Because this function attempts to send completed lines to the underlying
-    /// writer, it will also flush the existing buffer if it contains any
-    /// newlines.
-    ///
-    /// Because sorting through an array of `IoSlice` can be a bit convoluted,
-    /// This method differs from write in the following ways:
-    ///
-    /// - It attempts to write the full content of all the buffers up to and
-    ///   including the one containing the last newline. This means that it
-    ///   may attempt to write a partial line, that buffer has data past the
-    ///   newline.
-    /// - If the write only reports partial success, it does not attempt to
-    ///   find the precise location of the written bytes and buffer the rest.
-    ///
-    /// If the underlying vector doesn't support vectored writing, we instead
-    /// simply write the first non-empty buffer with `write`. This way, we
-    /// get the benefits of more granular partial-line handling without losing
-    /// anything in efficiency
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        // If there's no specialized behavior for write_vectored, just use
-        // write. This has the benefit of more granular partial-line handling.
-        if !self.is_write_vectored() {
-            return match bufs.iter().find(|buf| !buf.is_empty()) {
-                Some(buf) => self.write(buf),
-                None => Ok(0),
-            };
-        }
-
-        // Find the buffer containing the last newline
-        let last_newline_buf_idx = bufs
-            .iter()
-            .enumerate()
-            .rev()
-            .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i));
-
-        // If there are no new newlines (that is, if this write is less than
-        // one line), just do a regular buffered write
-        let last_newline_buf_idx = match last_newline_buf_idx {
-            // No newlines; just do a normal buffered write
-            None => {
-                self.flush_if_completed_line()?;
-                return self.buffer.write_vectored(bufs);
-            }
-            Some(i) => i,
-        };
-
-        // Flush existing content to prepare for our write
-        self.buffer.flush_buf()?;
-
-        // This is what we're going to try to write directly to the inner
-        // writer. The rest will be buffered, if nothing goes wrong.
-        let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1);
-
-        // Write `lines` directly to the inner writer. In keeping with the
-        // `write` convention, make at most one attempt to add new (unbuffered)
-        // data. Because this write doesn't touch the BufWriter state directly,
-        // and the buffer is known to be empty, we don't need to worry about
-        // self.panicked here.
-        let flushed = self.inner_mut().write_vectored(lines)?;
-
-        // If inner returns Ok(0), propagate that to the caller without
-        // doing additional buffering; otherwise we're just guaranteeing
-        // an "ErrorKind::WriteZero" later.
-        if flushed == 0 {
-            return Ok(0);
-        }
-
-        // Don't try to reconstruct the exact amount written; just bail
-        // in the event of a partial write
-        let lines_len = lines.iter().map(|buf| buf.len()).sum();
-        if flushed < lines_len {
-            return Ok(flushed);
-        }
-
-        // Now that the write has succeeded, buffer the rest (or as much of the
-        // rest as possible)
-        let buffered: usize = tail
-            .iter()
-            .filter(|buf| !buf.is_empty())
-            .map(|buf| self.buffer.write_to_buf(buf))
-            .take_while(|&n| n > 0)
-            .sum();
-
-        Ok(flushed + buffered)
-    }
-
-    fn is_write_vectored(&self) -> bool {
-        self.buffer.is_write_vectored()
-    }
-
-    /// Write some data into this BufReader with line buffering. This means
-    /// that, if any newlines are present in the data, the data up to the last
-    /// newline is sent directly to the underlying writer, and data after it
-    /// is buffered.
-    ///
-    /// Because this function attempts to send completed lines to the underlying
-    /// writer, it will also flush the existing buffer if it contains any
-    /// newlines, even if the incoming data does not contain any newlines.
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        match memchr::memrchr(b'\n', buf) {
-            // If there are no new newlines (that is, if this write is less than
-            // one line), just do a regular buffered write (which may flush if
-            // we exceed the inner buffer's size)
-            None => {
-                self.flush_if_completed_line()?;
-                self.buffer.write_all(buf)
-            }
-            Some(newline_idx) => {
-                let (lines, tail) = buf.split_at(newline_idx + 1);
-
-                if self.buffered().is_empty() {
-                    self.inner_mut().write_all(lines)?;
-                } else {
-                    // If there is any buffered data, we add the incoming lines
-                    // to that buffer before flushing, which saves us at least
-                    // one write call. We can't really do this with `write`,
-                    // since we can't do this *and* not suppress errors *and*
-                    // report a consistent state to the caller in a return
-                    // value, but here in write_all it's fine.
-                    self.buffer.write_all(lines)?;
-                    self.buffer.flush_buf()?;
-                }
-
-                self.buffer.write_all(tail)
-            }
-        }
-    }
-}
-
-/// Wraps a writer and buffers output to it, flushing whenever a newline
-/// (`0x0a`, `'\n'`) is detected.
-///
-/// The [`BufWriter`] struct wraps a writer and buffers its output.
-/// But it only does this batched write when it goes out of scope, or when the
-/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
-/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
-/// does exactly that.
-///
-/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
-/// `LineWriter` goes out of scope or when its internal buffer is full.
-///
-/// If there's still a partial line in the buffer when the `LineWriter` is
-/// dropped, it will flush those contents.
-///
-/// # Examples
-///
-/// We can use `LineWriter` to write one line at a time, significantly
-/// reducing the number of actual writes to the file.
-///
-/// ```no_run
-/// use std::fs::{self, File};
-/// use std::io::prelude::*;
-/// use std::io::LineWriter;
-///
-/// fn main() -> std::io::Result<()> {
-///     let road_not_taken = b"I shall be telling this with a sigh
-/// Somewhere ages and ages hence:
-/// Two roads diverged in a wood, and I -
-/// I took the one less traveled by,
-/// And that has made all the difference.";
-///
-///     let file = File::create("poem.txt")?;
-///     let mut file = LineWriter::new(file);
-///
-///     file.write_all(b"I shall be telling this with a sigh")?;
-///
-///     // No bytes are written until a newline is encountered (or
-///     // the internal buffer is filled).
-///     assert_eq!(fs::read_to_string("poem.txt")?, "");
-///     file.write_all(b"\n")?;
-///     assert_eq!(
-///         fs::read_to_string("poem.txt")?,
-///         "I shall be telling this with a sigh\n",
-///     );
-///
-///     // Write the rest of the poem.
-///     file.write_all(b"Somewhere ages and ages hence:
-/// Two roads diverged in a wood, and I -
-/// I took the one less traveled by,
-/// And that has made all the difference.")?;
-///
-///     // The last line of the poem doesn't end in a newline, so
-///     // we have to flush or drop the `LineWriter` to finish
-///     // writing.
-///     file.flush()?;
-///
-///     // Confirm the whole poem was written.
-///     assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct LineWriter<W: Write> {
-    inner: BufWriter<W>,
-}
-
-impl<W: Write> LineWriter<W> {
-    /// Creates a new `LineWriter`.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let file = LineWriter::new(file);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new(inner: W) -> LineWriter<W> {
-        // Lines typically aren't that long, don't use a giant buffer
-        LineWriter::with_capacity(1024, inner)
-    }
-
-    /// Creates a new `LineWriter` with a specified capacity for the internal
-    /// buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let file = LineWriter::with_capacity(100, file);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> {
-        LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
-    }
-
-    /// Gets a reference to the underlying writer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let file = LineWriter::new(file);
-    ///
-    ///     let reference = file.get_ref();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &W {
-        self.inner.get_ref()
-    }
-
-    /// Gets a mutable reference to the underlying writer.
-    ///
-    /// Caution must be taken when calling methods on the mutable reference
-    /// returned as extra writes could corrupt the output stream.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let mut file = LineWriter::new(file);
-    ///
-    ///     // we can use reference just like file
-    ///     let reference = file.get_mut();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut W {
-        self.inner.get_mut()
-    }
-
-    /// Unwraps this `LineWriter`, returning the underlying writer.
-    ///
-    /// The internal buffer is written out before returning the writer.
-    ///
-    /// # Errors
-    ///
-    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///
-    ///     let writer: LineWriter<File> = LineWriter::new(file);
-    ///
-    ///     let file: File = writer.into_inner()?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
-        self.inner
-            .into_inner()
-            .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for LineWriter<W> {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        LineWriterShim::new(&mut self.inner).write(buf)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.inner.flush()
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        LineWriterShim::new(&mut self.inner).write_vectored(bufs)
-    }
-
-    fn is_write_vectored(&self) -> bool {
-        self.inner.is_write_vectored()
-    }
-
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        LineWriterShim::new(&mut self.inner).write_all(buf)
-    }
-
-    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
-        LineWriterShim::new(&mut self.inner).write_all_vectored(bufs)
-    }
-
-    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
-        LineWriterShim::new(&mut self.inner).write_fmt(fmt)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for LineWriter<W>
-where
-    W: fmt::Debug,
-{
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_struct("LineWriter")
-            .field("writer", &self.inner.inner)
-            .field(
-                "buffer",
-                &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity()),
-            )
-            .finish()
-    }
-}
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
new file mode 100644
index 0000000..8fe29f0
--- /dev/null
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -0,0 +1,423 @@
+use crate::cmp;
+use crate::fmt;
+use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
+
+/// The `BufReader<R>` struct adds buffering to any reader.
+///
+/// It can be excessively inefficient to work directly with a [`Read`] instance.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader<R>` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
+///
+/// `BufReader<R>` can improve the speed of programs that make *small* and
+/// *repeated* read calls to the same file or network socket. It does not
+/// help when reading very large amounts at once, or reading just one or a few
+/// times. It also provides no advantage when reading from a source that is
+/// already in memory, like a [`Vec`]`<u8>`.
+///
+/// When the `BufReader<R>` is dropped, the contents of its buffer will be
+/// discarded. Creating multiple instances of a `BufReader<R>` on the same
+/// stream can cause data loss. Reading from the underlying reader after
+/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause
+/// data loss.
+///
+/// [`TcpStream::read`]: Read::read
+/// [`TcpStream`]: crate::net::TcpStream
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufReader;
+/// use std::fs::File;
+///
+/// fn main() -> std::io::Result<()> {
+///     let f = File::open("log.txt")?;
+///     let mut reader = BufReader::new(f);
+///
+///     let mut line = String::new();
+///     let len = reader.read_line(&mut line)?;
+///     println!("First line is {} bytes long", len);
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct BufReader<R> {
+    inner: R,
+    buf: Box<[u8]>,
+    pos: usize,
+    cap: usize,
+}
+
+impl<R: Read> BufReader<R> {
+    /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB,
+    /// but may change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(inner: R) -> BufReader<R> {
+        BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufReader<R>` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with ten bytes of capacity:
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let reader = BufReader::with_capacity(10, f);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
+        unsafe {
+            let mut buffer = Vec::with_capacity(capacity);
+            buffer.set_len(capacity);
+            inner.initializer().initialize(&mut buffer);
+            BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 }
+        }
+    }
+}
+
+impl<R> BufReader<R> {
+    /// Gets a reference to the underlying reader.
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_ref(&self) -> &R {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying reader.
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_mut(&mut self) -> &mut R {
+        &mut self.inner
+    }
+
+    /// Returns a reference to the internally buffered data.
+    ///
+    /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty.
+    ///
+    /// [`fill_buf`]: BufRead::fill_buf
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::{BufReader, BufRead};
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f);
+    ///     assert!(reader.buffer().is_empty());
+    ///
+    ///     if reader.fill_buf()?.len() > 0 {
+    ///         assert!(!reader.buffer().is_empty());
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
+    pub fn buffer(&self) -> &[u8] {
+        &self.buf[self.pos..self.cap]
+    }
+
+    /// Returns the number of bytes the internal buffer can hold at once.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::{BufReader, BufRead};
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f);
+    ///
+    ///     let capacity = reader.capacity();
+    ///     let buffer = reader.fill_buf()?;
+    ///     assert!(buffer.len() <= capacity);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
+    pub fn capacity(&self) -> usize {
+        self.buf.len()
+    }
+
+    /// Unwraps this `BufReader<R>`, returning the underlying reader.
+    ///
+    /// Note that any leftover data in the internal buffer is lost. Therefore,
+    /// a following read from the underlying reader may lead to data loss.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.into_inner();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(self) -> R {
+        self.inner
+    }
+
+    /// Invalidates all data in the internal buffer.
+    #[inline]
+    fn discard_buffer(&mut self) {
+        self.pos = 0;
+        self.cap = 0;
+    }
+}
+
+impl<R: Seek> BufReader<R> {
+    /// Seeks relative to the current position. If the new position lies within the buffer,
+    /// the buffer will not be flushed, allowing for more efficient seeks.
+    /// This method does not return the location of the underlying reader, so the caller
+    /// must track this information themselves if it is required.
+    #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
+    pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+        let pos = self.pos as u64;
+        if offset < 0 {
+            if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+                self.pos = new_pos as usize;
+                return Ok(());
+            }
+        } else {
+            if let Some(new_pos) = pos.checked_add(offset as u64) {
+                if new_pos <= self.cap as u64 {
+                    self.pos = new_pos as usize;
+                    return Ok(());
+                }
+            }
+        }
+        self.seek(SeekFrom::Current(offset)).map(drop)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> Read for BufReader<R> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        // If we don't have any buffered data and we're doing a massive read
+        // (larger than our internal buffer), bypass our internal buffer
+        // entirely.
+        if self.pos == self.cap && buf.len() >= self.buf.len() {
+            self.discard_buffer();
+            return self.inner.read(buf);
+        }
+        let nread = {
+            let mut rem = self.fill_buf()?;
+            rem.read(buf)?
+        };
+        self.consume(nread);
+        Ok(nread)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
+        if self.pos == self.cap && total_len >= self.buf.len() {
+            self.discard_buffer();
+            return self.inner.read_vectored(bufs);
+        }
+        let nread = {
+            let mut rem = self.fill_buf()?;
+            rem.read_vectored(bufs)?
+        };
+        self.consume(nread);
+        Ok(nread)
+    }
+
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    // we can't skip unconditionally because of the large buffer case in read.
+    unsafe fn initializer(&self) -> Initializer {
+        self.inner.initializer()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> BufRead for BufReader<R> {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> {
+        // If we've reached the end of our internal buffer then we need to fetch
+        // some more data from the underlying reader.
+        // Branch using `>=` instead of the more correct `==`
+        // to tell the compiler that the pos..cap slice is always valid.
+        if self.pos >= self.cap {
+            debug_assert!(self.pos == self.cap);
+            self.cap = self.inner.read(&mut self.buf)?;
+            self.pos = 0;
+        }
+        Ok(&self.buf[self.pos..self.cap])
+    }
+
+    fn consume(&mut self, amt: usize) {
+        self.pos = cmp::min(self.pos + amt, self.cap);
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R> fmt::Debug for BufReader<R>
+where
+    R: fmt::Debug,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("BufReader")
+            .field("reader", &self.inner)
+            .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
+            .finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Seek> Seek for BufReader<R> {
+    /// Seek to an offset, in bytes, in the underlying reader.
+    ///
+    /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
+    /// position the underlying reader would be at if the `BufReader<R>` had no
+    /// internal buffer.
+    ///
+    /// Seeking always discards the internal buffer, even if the seek position
+    /// would otherwise fall within it. This guarantees that calling
+    /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
+    /// at the same position.
+    ///
+    /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
+    ///
+    /// See [`std::io::Seek`] for more details.
+    ///
+    /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
+    /// where `n` minus the internal buffer length overflows an `i64`, two
+    /// seeks will be performed instead of one. If the second seek returns
+    /// [`Err`], the underlying reader will be left at the same position it would
+    /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
+    ///
+    /// [`std::io::Seek`]: Seek
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        let result: u64;
+        if let SeekFrom::Current(n) = pos {
+            let remainder = (self.cap - self.pos) as i64;
+            // it should be safe to assume that remainder fits within an i64 as the alternative
+            // means we managed to allocate 8 exbibytes and that's absurd.
+            // But it's not out of the realm of possibility for some weird underlying reader to
+            // support seeking by i64::MIN so we need to handle underflow when subtracting
+            // remainder.
+            if let Some(offset) = n.checked_sub(remainder) {
+                result = self.inner.seek(SeekFrom::Current(offset))?;
+            } else {
+                // seek backwards by our remainder, and then by the offset
+                self.inner.seek(SeekFrom::Current(-remainder))?;
+                self.discard_buffer();
+                result = self.inner.seek(SeekFrom::Current(n))?;
+            }
+        } else {
+            // Seeking with Start/End doesn't care about our buffer length.
+            result = self.inner.seek(pos)?;
+        }
+        self.discard_buffer();
+        Ok(result)
+    }
+
+    /// Returns the current seek position from the start of the stream.
+    ///
+    /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
+    /// but does not flush the internal buffer. Due to this optimization the
+    /// function does not guarantee that calling `.into_inner()` immediately
+    /// afterwards will yield the underlying reader at the same position. Use
+    /// [`BufReader::seek`] instead if you require that guarantee.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if the position of the inner reader is smaller
+    /// than the amount of buffered data. That can happen if the inner reader
+    /// has an incorrect implementation of [`Seek::stream_position`], or if the
+    /// position has gone out of sync due to calling [`Seek::seek`] directly on
+    /// the underlying reader.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(seek_convenience)]
+    /// use std::{
+    ///     io::{self, BufRead, BufReader, Seek},
+    ///     fs::File,
+    /// };
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = BufReader::new(File::open("foo.txt")?);
+    ///
+    ///     let before = f.stream_position()?;
+    ///     f.read_line(&mut String::new())?;
+    ///     let after = f.stream_position()?;
+    ///
+    ///     println!("The first line was {} bytes long", after - before);
+    ///     Ok(())
+    /// }
+    /// ```
+    fn stream_position(&mut self) -> io::Result<u64> {
+        let remainder = (self.cap - self.pos) as u64;
+        self.inner.stream_position().map(|pos| {
+            pos.checked_sub(remainder).expect(
+                "overflow when subtracting remaining buffer size from inner stream position",
+            )
+        })
+    }
+}
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
new file mode 100644
index 0000000..8ce795a
--- /dev/null
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -0,0 +1,387 @@
+use crate::fmt;
+use crate::io::{
+    self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
+};
+
+/// Wraps a writer and buffers its output.
+///
+/// It can be excessively inefficient to work directly with something that
+/// implements [`Write`]. For example, every call to
+/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
+///
+/// `BufWriter<W>` can improve the speed of programs that make *small* and
+/// *repeated* write calls to the same file or network socket. It does not
+/// help when writing very large amounts at once, or writing just one or a few
+/// times. It also provides no advantage when writing to a destination that is
+/// in memory, like a [`Vec`]<u8>`.
+///
+/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
+/// dropping will attempt to flush the contents of the buffer, any errors
+/// that happen in the process of dropping will be ignored. Calling [`flush`]
+/// ensures that the buffer is empty and thus dropping will not even attempt
+/// file operations.
+///
+/// # Examples
+///
+/// Let's write the numbers one through ten to a [`TcpStream`]:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+/// for i in 0..10 {
+///     stream.write(&[i+1]).unwrap();
+/// }
+/// ```
+///
+/// Because we're not buffering, we write each one in turn, incurring the
+/// overhead of a system call per byte written. We can fix this with a
+/// `BufWriter<W>`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// for i in 0..10 {
+///     stream.write(&[i+1]).unwrap();
+/// }
+/// stream.flush().unwrap();
+/// ```
+///
+/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped
+/// together by the buffer and will all be written out in one system call when
+/// the `stream` is flushed.
+///
+/// [`TcpStream::write`]: Write::write
+/// [`TcpStream`]: crate::net::TcpStream
+/// [`flush`]: Write::flush
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct BufWriter<W: Write> {
+    inner: Option<W>,
+    buf: Vec<u8>,
+    // #30888: If the inner writer panics in a call to write, we don't want to
+    // write the buffered data a second time in BufWriter's destructor. This
+    // flag tells the Drop impl if it should skip the flush.
+    panicked: bool,
+}
+
+impl<W: Write> BufWriter<W> {
+    /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB,
+    /// but may change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(inner: W) -> BufWriter<W> {
+        BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufWriter<W>` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with a buffer of a hundred bytes.
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+    /// let mut buffer = BufWriter::with_capacity(100, stream);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> {
+        BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false }
+    }
+
+    /// Send data in our local buffer into the inner writer, looping as
+    /// necessary until either it's all been sent or an error occurs.
+    ///
+    /// Because all the data in the buffer has been reported to our owner as
+    /// "successfully written" (by returning nonzero success values from
+    /// `write`), any 0-length writes from `inner` must be reported as i/o
+    /// errors from this method.
+    pub(super) fn flush_buf(&mut self) -> io::Result<()> {
+        /// Helper struct to ensure the buffer is updated after all the writes
+        /// are complete. It tracks the number of written bytes and drains them
+        /// all from the front of the buffer when dropped.
+        struct BufGuard<'a> {
+            buffer: &'a mut Vec<u8>,
+            written: usize,
+        }
+
+        impl<'a> BufGuard<'a> {
+            fn new(buffer: &'a mut Vec<u8>) -> Self {
+                Self { buffer, written: 0 }
+            }
+
+            /// The unwritten part of the buffer
+            fn remaining(&self) -> &[u8] {
+                &self.buffer[self.written..]
+            }
+
+            /// Flag some bytes as removed from the front of the buffer
+            fn consume(&mut self, amt: usize) {
+                self.written += amt;
+            }
+
+            /// true if all of the bytes have been written
+            fn done(&self) -> bool {
+                self.written >= self.buffer.len()
+            }
+        }
+
+        impl Drop for BufGuard<'_> {
+            fn drop(&mut self) {
+                if self.written > 0 {
+                    self.buffer.drain(..self.written);
+                }
+            }
+        }
+
+        let mut guard = BufGuard::new(&mut self.buf);
+        let inner = self.inner.as_mut().unwrap();
+        while !guard.done() {
+            self.panicked = true;
+            let r = inner.write(guard.remaining());
+            self.panicked = false;
+
+            match r {
+                Ok(0) => {
+                    return Err(Error::new(
+                        ErrorKind::WriteZero,
+                        "failed to write the buffered data",
+                    ));
+                }
+                Ok(n) => guard.consume(n),
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+
+    /// Buffer some data without flushing it, regardless of the size of the
+    /// data. Writes as much as possible without exceeding capacity. Returns
+    /// the number of bytes written.
+    pub(super) fn write_to_buf(&mut self, buf: &[u8]) -> usize {
+        let available = self.buf.capacity() - self.buf.len();
+        let amt_to_buffer = available.min(buf.len());
+        self.buf.extend_from_slice(&buf[..amt_to_buffer]);
+        amt_to_buffer
+    }
+
+    /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_ref();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_ref(&self) -> &W {
+        self.inner.as_ref().unwrap()
+    }
+
+    /// Gets a mutable reference to the underlying writer.
+    ///
+    /// It is inadvisable to directly write to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_mut();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_mut(&mut self) -> &mut W {
+        self.inner.as_mut().unwrap()
+    }
+
+    /// Returns a reference to the internally buffered data.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // See how many bytes are currently buffered
+    /// let bytes_buffered = buf_writer.buffer().len();
+    /// ```
+    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
+    pub fn buffer(&self) -> &[u8] {
+        &self.buf
+    }
+
+    /// Returns the number of bytes the internal buffer can hold without flushing.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // Check the capacity of the inner buffer
+    /// let capacity = buf_writer.capacity();
+    /// // Calculate how many bytes can be written without flushing
+    /// let without_flush = capacity - buf_writer.buffer().len();
+    /// ```
+    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
+    pub fn capacity(&self) -> usize {
+        self.buf.capacity()
+    }
+
+    /// Unwraps this `BufWriter<W>`, returning the underlying writer.
+    ///
+    /// The buffer is written out before returning the writer.
+    ///
+    /// # Errors
+    ///
+    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // unwrap the TcpStream and flush the buffer
+    /// let stream = buffer.into_inner().unwrap();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
+        match self.flush_buf() {
+            Err(e) => Err(IntoInnerError::new(self, e)),
+            Ok(()) => Ok(self.inner.take().unwrap()),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Write for BufWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if self.buf.len() + buf.len() > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write(buf);
+            self.panicked = false;
+            r
+        } else {
+            self.buf.extend_from_slice(buf);
+            Ok(buf.len())
+        }
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        // Normally, `write_all` just calls `write` in a loop. We can do better
+        // by calling `self.get_mut().write_all()` directly, which avoids
+        // round trips through the buffer in the event of a series of partial
+        // writes in some circumstances.
+        if self.buf.len() + buf.len() > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write_all(buf);
+            self.panicked = false;
+            r
+        } else {
+            self.buf.extend_from_slice(buf);
+            Ok(())
+        }
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
+        if self.buf.len() + total_len > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
+        if total_len >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write_vectored(bufs);
+            self.panicked = false;
+            r
+        } else {
+            bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
+            Ok(total_len)
+        }
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        self.get_ref().is_write_vectored()
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.flush_buf().and_then(|()| self.get_mut().flush())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> fmt::Debug for BufWriter<W>
+where
+    W: fmt::Debug,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("BufWriter")
+            .field("writer", &self.inner.as_ref().unwrap())
+            .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
+            .finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write + Seek> Seek for BufWriter<W> {
+    /// Seek to the offset, in bytes, in the underlying writer.
+    ///
+    /// Seeking always writes out the internal buffer before seeking.
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        self.flush_buf()?;
+        self.get_mut().seek(pos)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Drop for BufWriter<W> {
+    fn drop(&mut self) {
+        if self.inner.is_some() && !self.panicked {
+            // dtors should not panic, so we ignore a failed flush
+            let _r = self.flush_buf();
+        }
+    }
+}
diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs
new file mode 100644
index 0000000..502c6e3
--- /dev/null
+++ b/library/std/src/io/buffered/linewriter.rs
@@ -0,0 +1,232 @@
+use crate::fmt;
+use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSlice, Write};
+
+/// Wraps a writer and buffers output to it, flushing whenever a newline
+/// (`0x0a`, `'\n'`) is detected.
+///
+/// The [`BufWriter`] struct wraps a writer and buffers its output.
+/// But it only does this batched write when it goes out of scope, or when the
+/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
+/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
+/// does exactly that.
+///
+/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// `LineWriter` goes out of scope or when its internal buffer is full.
+///
+/// If there's still a partial line in the buffer when the `LineWriter` is
+/// dropped, it will flush those contents.
+///
+/// # Examples
+///
+/// We can use `LineWriter` to write one line at a time, significantly
+/// reducing the number of actual writes to the file.
+///
+/// ```no_run
+/// use std::fs::{self, File};
+/// use std::io::prelude::*;
+/// use std::io::LineWriter;
+///
+/// fn main() -> std::io::Result<()> {
+///     let road_not_taken = b"I shall be telling this with a sigh
+/// Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.";
+///
+///     let file = File::create("poem.txt")?;
+///     let mut file = LineWriter::new(file);
+///
+///     file.write_all(b"I shall be telling this with a sigh")?;
+///
+///     // No bytes are written until a newline is encountered (or
+///     // the internal buffer is filled).
+///     assert_eq!(fs::read_to_string("poem.txt")?, "");
+///     file.write_all(b"\n")?;
+///     assert_eq!(
+///         fs::read_to_string("poem.txt")?,
+///         "I shall be telling this with a sigh\n",
+///     );
+///
+///     // Write the rest of the poem.
+///     file.write_all(b"Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.")?;
+///
+///     // The last line of the poem doesn't end in a newline, so
+///     // we have to flush or drop the `LineWriter` to finish
+///     // writing.
+///     file.flush()?;
+///
+///     // Confirm the whole poem was written.
+///     assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct LineWriter<W: Write> {
+    inner: BufWriter<W>,
+}
+
+impl<W: Write> LineWriter<W> {
+    /// Creates a new `LineWriter`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::new(file);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(inner: W) -> LineWriter<W> {
+        // Lines typically aren't that long, don't use a giant buffer
+        LineWriter::with_capacity(1024, inner)
+    }
+
+    /// Creates a new `LineWriter` with a specified capacity for the internal
+    /// buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::with_capacity(100, file);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> {
+        LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
+    }
+
+    /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::new(file);
+    ///
+    ///     let reference = file.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_ref(&self) -> &W {
+        self.inner.get_ref()
+    }
+
+    /// Gets a mutable reference to the underlying writer.
+    ///
+    /// Caution must be taken when calling methods on the mutable reference
+    /// returned as extra writes could corrupt the output stream.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let mut file = LineWriter::new(file);
+    ///
+    ///     // we can use reference just like file
+    ///     let reference = file.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_mut(&mut self) -> &mut W {
+        self.inner.get_mut()
+    }
+
+    /// Unwraps this `LineWriter`, returning the underlying writer.
+    ///
+    /// The internal buffer is written out before returning the writer.
+    ///
+    /// # Errors
+    ///
+    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///
+    ///     let writer: LineWriter<File> = LineWriter::new(file);
+    ///
+    ///     let file: File = writer.into_inner()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
+        self.inner.into_inner().map_err(|err| err.new_wrapped(|inner| LineWriter { inner }))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Write for LineWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        LineWriterShim::new(&mut self.inner).write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        LineWriterShim::new(&mut self.inner).write_vectored(bufs)
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_all(buf)
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_all_vectored(bufs)
+    }
+
+    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_fmt(fmt)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> fmt::Debug for LineWriter<W>
+where
+    W: fmt::Debug,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("LineWriter")
+            .field("writer", &self.get_ref())
+            .field(
+                "buffer",
+                &format_args!("{}/{}", self.inner.buffer().len(), self.inner.capacity()),
+            )
+            .finish()
+    }
+}
diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs
new file mode 100644
index 0000000..a80d08d
--- /dev/null
+++ b/library/std/src/io/buffered/linewritershim.rs
@@ -0,0 +1,270 @@
+use crate::io::{self, BufWriter, IoSlice, Write};
+use crate::memchr;
+
+/// Private helper struct for implementing the line-buffered writing logic.
+/// This shim temporarily wraps a BufWriter, and uses its internals to
+/// implement a line-buffered writer (specifically by using the internal
+/// methods like write_to_buf and flush_buf). In this way, a more
+/// efficient abstraction can be created than one that only had access to
+/// `write` and `flush`, without needlessly duplicating a lot of the
+/// implementation details of BufWriter. This also allows existing
+/// `BufWriters` to be temporarily given line-buffering logic; this is what
+/// enables Stdout to be alternately in line-buffered or block-buffered mode.
+#[derive(Debug)]
+pub struct LineWriterShim<'a, W: Write> {
+    buffer: &'a mut BufWriter<W>,
+}
+
+impl<'a, W: Write> LineWriterShim<'a, W> {
+    pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
+        Self { buffer }
+    }
+
+    /// Get a mutable reference to the inner writer (that is, the writer
+    /// wrapped by the BufWriter). Be careful with this writer, as writes to
+    /// it will bypass the buffer.
+    fn inner_mut(&mut self) -> &mut W {
+        self.buffer.get_mut()
+    }
+
+    /// Get the content currently buffered in self.buffer
+    fn buffered(&self) -> &[u8] {
+        self.buffer.buffer()
+    }
+
+    /// Flush the buffer iff the last byte is a newline (indicating that an
+    /// earlier write only succeeded partially, and we want to retry flushing
+    /// the buffered line before continuing with a subsequent write)
+    fn flush_if_completed_line(&mut self) -> io::Result<()> {
+        match self.buffered().last().copied() {
+            Some(b'\n') => self.buffer.flush_buf(),
+            _ => Ok(()),
+        }
+    }
+}
+
+impl<'a, W: Write> Write for LineWriterShim<'a, W> {
+    /// Write some data into this BufReader with line buffering. This means
+    /// that, if any newlines are present in the data, the data up to the last
+    /// newline is sent directly to the underlying writer, and data after it
+    /// is buffered. Returns the number of bytes written.
+    ///
+    /// This function operates on a "best effort basis"; in keeping with the
+    /// convention of `Write::write`, it makes at most one attempt to write
+    /// new data to the underlying writer. If that write only reports a partial
+    /// success, the remaining data will be buffered.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it ends with a
+    /// newline, even if the incoming data does not contain any newlines.
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let newline_idx = match memchr::memrchr(b'\n', buf) {
+            // If there are no new newlines (that is, if this write is less than
+            // one line), just do a regular buffered write (which may flush if
+            // we exceed the inner buffer's size)
+            None => {
+                self.flush_if_completed_line()?;
+                return self.buffer.write(buf);
+            }
+            // Otherwise, arrange for the lines to be written directly to the
+            // inner writer.
+            Some(newline_idx) => newline_idx + 1,
+        };
+
+        // Flush existing content to prepare for our write. We have to do this
+        // before attempting to write `buf` in order to maintain consistency;
+        // if we add `buf` to the buffer then try to flush it all at once,
+        // we're obligated to return Ok(), which would mean suppressing any
+        // errors that occur during flush.
+        self.buffer.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let lines = &buf[..newline_idx];
+
+        // Write `lines` directly to the inner writer. In keeping with the
+        // `write` convention, make at most one attempt to add new (unbuffered)
+        // data. Because this write doesn't touch the BufWriter state directly,
+        // and the buffer is known to be empty, we don't need to worry about
+        // self.buffer.panicked here.
+        let flushed = self.inner_mut().write(lines)?;
+
+        // If buffer returns Ok(0), propagate that to the caller without
+        // doing additional buffering; otherwise we're just guaranteeing
+        // an "ErrorKind::WriteZero" later.
+        if flushed == 0 {
+            return Ok(0);
+        }
+
+        // Now that the write has succeeded, buffer the rest (or as much of
+        // the rest as possible). If there were any unwritten newlines, we
+        // only buffer out to the last unwritten newline that fits in the
+        // buffer; this helps prevent flushing partial lines on subsequent
+        // calls to LineWriterShim::write.
+
+        // Handle the cases in order of most-common to least-common, under
+        // the presumption that most writes succeed in totality, and that most
+        // writes are smaller than the buffer.
+        // - Is this a partial line (ie, no newlines left in the unwritten tail)
+        // - If not, does the data out to the last unwritten newline fit in
+        //   the buffer?
+        // - If not, scan for the last newline that *does* fit in the buffer
+        let tail = if flushed >= newline_idx {
+            &buf[flushed..]
+        } else if newline_idx - flushed <= self.buffer.capacity() {
+            &buf[flushed..newline_idx]
+        } else {
+            let scan_area = &buf[flushed..];
+            let scan_area = &scan_area[..self.buffer.capacity()];
+            match memchr::memrchr(b'\n', scan_area) {
+                Some(newline_idx) => &scan_area[..newline_idx + 1],
+                None => scan_area,
+            }
+        };
+
+        let buffered = self.buffer.write_to_buf(tail);
+        Ok(flushed + buffered)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.buffer.flush()
+    }
+
+    /// Write some vectored data into this BufReader with line buffering. This
+    /// means that, if any newlines are present in the data, the data up to
+    /// and including the buffer containing the last newline is sent directly
+    /// to the inner writer, and the data after it is buffered. Returns the
+    /// number of bytes written.
+    ///
+    /// This function operates on a "best effort basis"; in keeping with the
+    /// convention of `Write::write`, it makes at most one attempt to write
+    /// new data to the underlying writer.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it contains any
+    /// newlines.
+    ///
+    /// Because sorting through an array of `IoSlice` can be a bit convoluted,
+    /// This method differs from write in the following ways:
+    ///
+    /// - It attempts to write the full content of all the buffers up to and
+    ///   including the one containing the last newline. This means that it
+    ///   may attempt to write a partial line, that buffer has data past the
+    ///   newline.
+    /// - If the write only reports partial success, it does not attempt to
+    ///   find the precise location of the written bytes and buffer the rest.
+    ///
+    /// If the underlying vector doesn't support vectored writing, we instead
+    /// simply write the first non-empty buffer with `write`. This way, we
+    /// get the benefits of more granular partial-line handling without losing
+    /// anything in efficiency
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        // If there's no specialized behavior for write_vectored, just use
+        // write. This has the benefit of more granular partial-line handling.
+        if !self.is_write_vectored() {
+            return match bufs.iter().find(|buf| !buf.is_empty()) {
+                Some(buf) => self.write(buf),
+                None => Ok(0),
+            };
+        }
+
+        // Find the buffer containing the last newline
+        let last_newline_buf_idx = bufs
+            .iter()
+            .enumerate()
+            .rev()
+            .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i));
+
+        // If there are no new newlines (that is, if this write is less than
+        // one line), just do a regular buffered write
+        let last_newline_buf_idx = match last_newline_buf_idx {
+            // No newlines; just do a normal buffered write
+            None => {
+                self.flush_if_completed_line()?;
+                return self.buffer.write_vectored(bufs);
+            }
+            Some(i) => i,
+        };
+
+        // Flush existing content to prepare for our write
+        self.buffer.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1);
+
+        // Write `lines` directly to the inner writer. In keeping with the
+        // `write` convention, make at most one attempt to add new (unbuffered)
+        // data. Because this write doesn't touch the BufWriter state directly,
+        // and the buffer is known to be empty, we don't need to worry about
+        // self.panicked here.
+        let flushed = self.inner_mut().write_vectored(lines)?;
+
+        // If inner returns Ok(0), propagate that to the caller without
+        // doing additional buffering; otherwise we're just guaranteeing
+        // an "ErrorKind::WriteZero" later.
+        if flushed == 0 {
+            return Ok(0);
+        }
+
+        // Don't try to reconstruct the exact amount written; just bail
+        // in the event of a partial write
+        let lines_len = lines.iter().map(|buf| buf.len()).sum();
+        if flushed < lines_len {
+            return Ok(flushed);
+        }
+
+        // Now that the write has succeeded, buffer the rest (or as much of the
+        // rest as possible)
+        let buffered: usize = tail
+            .iter()
+            .filter(|buf| !buf.is_empty())
+            .map(|buf| self.buffer.write_to_buf(buf))
+            .take_while(|&n| n > 0)
+            .sum();
+
+        Ok(flushed + buffered)
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        self.buffer.is_write_vectored()
+    }
+
+    /// Write some data into this BufReader with line buffering. This means
+    /// that, if any newlines are present in the data, the data up to the last
+    /// newline is sent directly to the underlying writer, and data after it
+    /// is buffered.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it contains any
+    /// newlines, even if the incoming data does not contain any newlines.
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        match memchr::memrchr(b'\n', buf) {
+            // If there are no new newlines (that is, if this write is less than
+            // one line), just do a regular buffered write (which may flush if
+            // we exceed the inner buffer's size)
+            None => {
+                self.flush_if_completed_line()?;
+                self.buffer.write_all(buf)
+            }
+            Some(newline_idx) => {
+                let (lines, tail) = buf.split_at(newline_idx + 1);
+
+                if self.buffered().is_empty() {
+                    self.inner_mut().write_all(lines)?;
+                } else {
+                    // If there is any buffered data, we add the incoming lines
+                    // to that buffer before flushing, which saves us at least
+                    // one write call. We can't really do this with `write`,
+                    // since we can't do this *and* not suppress errors *and*
+                    // report a consistent state to the caller in a return
+                    // value, but here in write_all it's fine.
+                    self.buffer.write_all(lines)?;
+                    self.buffer.flush_buf()?;
+                }
+
+                self.buffer.write_all(tail)
+            }
+        }
+    }
+}
diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs
new file mode 100644
index 0000000..f9caeaf
--- /dev/null
+++ b/library/std/src/io/buffered/mod.rs
@@ -0,0 +1,151 @@
+//! Buffering wrappers for I/O traits
+
+mod bufreader;
+mod bufwriter;
+mod linewriter;
+mod linewritershim;
+
+#[cfg(test)]
+mod tests;
+
+use crate::error;
+use crate::fmt;
+use crate::io::Error;
+
+pub use bufreader::BufReader;
+pub use bufwriter::BufWriter;
+pub use linewriter::LineWriter;
+use linewritershim::LineWriterShim;
+
+/// An error returned by [`BufWriter::into_inner`] which combines an error that
+/// happened while writing out the buffer, and the buffered writer object
+/// which may be used to recover from the condition.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// // do stuff with the stream
+///
+/// // we want to get our `TcpStream` back, so let's try:
+///
+/// let stream = match stream.into_inner() {
+///     Ok(s) => s,
+///     Err(e) => {
+///         // Here, e is an IntoInnerError
+///         panic!("An error occurred");
+///     }
+/// };
+/// ```
+#[derive(Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IntoInnerError<W>(W, Error);
+
+impl<W> IntoInnerError<W> {
+    /// Construct a new IntoInnerError
+    fn new(writer: W, error: Error) -> Self {
+        Self(writer, error)
+    }
+
+    /// Helper to construct a new IntoInnerError; intended to help with
+    /// adapters that wrap other adapters
+    fn new_wrapped<W2>(self, f: impl FnOnce(W) -> W2) -> IntoInnerError<W2> {
+        let Self(writer, error) = self;
+        IntoInnerError::new(f(writer), error)
+    }
+
+    /// Returns the error which caused the call to [`BufWriter::into_inner()`]
+    /// to fail.
+    ///
+    /// This error was returned when attempting to write the internal buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is an IntoInnerError, let's log the inner error.
+    ///         //
+    ///         // We'll just 'log' to stdout for this example.
+    ///         println!("{}", e.error());
+    ///
+    ///         panic!("An unexpected error occurred.");
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn error(&self) -> &Error {
+        &self.1
+    }
+
+    /// Returns the buffered writer instance which generated the error.
+    ///
+    /// The returned object can be used for error recovery, such as
+    /// re-inspecting the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is an IntoInnerError, let's re-examine the buffer:
+    ///         let buffer = e.into_inner();
+    ///
+    ///         // do stuff to try to recover
+    ///
+    ///         // afterwards, let's just return the stream
+    ///         buffer.into_inner().unwrap()
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(self) -> W {
+        self.0
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> From<IntoInnerError<W>> for Error {
+    fn from(iie: IntoInnerError<W>) -> Error {
+        iie.1
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
+    #[allow(deprecated, deprecated_in_future)]
+    fn description(&self) -> &str {
+        error::Error::description(self.error())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> fmt::Display for IntoInnerError<W> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.error().fmt(f)
+    }
+}
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 61ccc6f..36b4940 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -9,6 +9,7 @@
 use crate::fmt;
 use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
 use crate::lazy::SyncOnceCell;
+use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::{Mutex, MutexGuard};
 use crate::sys::stdio;
 use crate::sys_common;
@@ -16,19 +17,33 @@
 use crate::thread::LocalKey;
 
 thread_local! {
-    /// Stdout used by print! and println! macros
+    /// Used by the test crate to capture the output of the print! and println! macros.
     static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
         RefCell::new(None)
     }
 }
 
 thread_local! {
-    /// Stderr used by eprint! and eprintln! macros, and panics
+    /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
     static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
         RefCell::new(None)
     }
 }
 
+/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
+///
+/// If both are None and were never set on any thread, this flag is set to
+/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all
+/// threads, saving some time and memory registering an unused thread local.
+///
+/// Note about memory ordering: This contains information about whether two
+/// thread local variables might be in use. Although this is a global flag, the
+/// memory ordering between threads does not matter: we only want this flag to
+/// have a consistent order between set_print/set_panic and print_to *within
+/// the same thread*. Within the same thread, things always have a perfectly
+/// consistent order. So Ordering::Relaxed is fine.
+static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false);
+
 /// A handle to a raw instance of the standard input stream of this process.
 ///
 /// This handle is not synchronized or buffered in any fashion. Constructed via
@@ -890,10 +905,18 @@
 #[doc(hidden)]
 pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
     use crate::mem;
-    LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| {
-        let _ = s.flush();
-        Some(s)
-    })
+    if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
+        // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
+        return None;
+    }
+    let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
+        |mut s| {
+            let _ = s.flush();
+            Some(s)
+        },
+    );
+    LOCAL_STREAMS.store(true, Ordering::Relaxed);
+    s
 }
 
 /// Resets the thread-local stdout handle to the specified writer
@@ -913,10 +936,18 @@
 #[doc(hidden)]
 pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
     use crate::mem;
-    LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| {
-        let _ = s.flush();
-        Some(s)
-    })
+    if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
+        // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
+        return None;
+    }
+    let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
+        |mut s| {
+            let _ = s.flush();
+            Some(s)
+        },
+    );
+    LOCAL_STREAMS.store(true, Ordering::Relaxed);
+    s
 }
 
 /// Write `args` to output stream `local_s` if possible, `global_s`
@@ -937,20 +968,26 @@
 ) where
     T: Write,
 {
-    let result = local_s
-        .try_with(|s| {
-            // Note that we completely remove a local sink to write to in case
-            // our printing recursively panics/prints, so the recursive
-            // panic/print goes to the global sink instead of our local sink.
-            let prev = s.borrow_mut().take();
-            if let Some(mut w) = prev {
-                let result = w.write_fmt(args);
-                *s.borrow_mut() = Some(w);
-                return result;
-            }
-            global_s().write_fmt(args)
+    let result = LOCAL_STREAMS
+        .load(Ordering::Relaxed)
+        .then(|| {
+            local_s
+                .try_with(|s| {
+                    // Note that we completely remove a local sink to write to in case
+                    // our printing recursively panics/prints, so the recursive
+                    // panic/print goes to the global sink instead of our local sink.
+                    let prev = s.borrow_mut().take();
+                    if let Some(mut w) = prev {
+                        let result = w.write_fmt(args);
+                        *s.borrow_mut() = Some(w);
+                        return result;
+                    }
+                    global_s().write_fmt(args)
+                })
+                .ok()
         })
-        .unwrap_or_else(|_| global_s().write_fmt(args));
+        .flatten()
+        .unwrap_or_else(|| global_s().write_fmt(args));
 
     if let Err(e) = result {
         panic!("failed printing to {}: {}", label, e);
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 54ce0e7..a4bbb18 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -102,7 +102,9 @@
 
 #[doc(keyword = "const")]
 //
-/// Compile-time constants and deterministic functions.
+/// Compile-time constants and compile-time evaluable functions.
+///
+/// ## Compile-time constants
 ///
 /// Sometimes a certain value is used many times throughout a program, and it can become
 /// inconvenient to copy it over and over. What's more, it's not always possible or desirable to
@@ -145,15 +147,28 @@
 ///
 /// Constants, like statics, should always be in `SCREAMING_SNAKE_CASE`.
 ///
+/// For more detail on `const`, see the [Rust Book] or the [Reference].
+///
+/// ## Compile-time evaluable functions
+///
+/// The other main use of the `const` keyword is in `const fn`. This marks a function as being
+/// callable in the body of a `const` or `static` item and in array initializers (commonly called
+/// "const contexts"). `const fn` are restricted in the set of operations they can perform, to
+/// ensure that they can be evaluated at compile-time. See the [Reference][const-eval] for more
+/// detail.
+///
+/// Turning a `fn` into a `const fn` has no effect on run-time uses of that function.
+///
+/// ## Other uses of `const`
+///
 /// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const
 /// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive].
 ///
-/// For more detail on `const`, see the [Rust Book] or the [Reference].
-///
 /// [pointer primitive]: primitive.pointer.html
 /// [Rust Book]:
 /// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
 /// [Reference]: ../reference/items/constant-items.html
+/// [const-eval]: ../reference/const_eval.html
 mod const_keyword {}
 
 #[doc(keyword = "continue")]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index d03428d..30e7a7f 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -85,7 +85,7 @@
 //! # Contributing changes to the documentation
 //!
 //! Check out the rust contribution guidelines [here](
-//! https://rustc-dev-guide.rust-lang.org/getting-started.html).
+//! https://rustc-dev-guide.rust-lang.org/contributing.html#writing-documentation).
 //! The source for this documentation can be found on
 //! [GitHub](https://github.com/rust-lang/rust).
 //! To contribute changes, make sure you read the guidelines first, then submit
@@ -226,6 +226,7 @@
 #![feature(asm)]
 #![feature(associated_type_bounds)]
 #![feature(atomic_mut_ptr)]
+#![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(c_variadic)]
 #![feature(cfg_accessible)]
@@ -236,9 +237,10 @@
 #![feature(clamp)]
 #![feature(concat_idents)]
 #![feature(const_cstr_unchecked)]
-#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))]
+#![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_fn_transmute)]
 #![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 #![feature(const_ip)]
 #![feature(const_ipv6)]
 #![feature(const_raw_ptr_deref)]
@@ -247,7 +249,6 @@
 #![feature(core_intrinsics)]
 #![feature(custom_test_frameworks)]
 #![feature(decl_macro)]
-#![cfg_attr(bootstrap, feature(doc_alias))]
 #![feature(doc_cfg)]
 #![feature(doc_keyword)]
 #![feature(doc_masked)]
@@ -318,7 +319,7 @@
 #![feature(unsafe_block_in_unsafe_fn)]
 #![feature(unsafe_cell_get_mut)]
 #![feature(unsafe_cell_raw_get)]
-#![feature(untagged_unions)]
+#![cfg_attr(bootstrap, feature(untagged_unions))]
 #![feature(unwind_attributes)]
 #![feature(vec_into_raw_parts)]
 #![feature(wake_trait)]
diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs
index e213963..63de871 100644
--- a/library/std/src/net/addr.rs
+++ b/library/std/src/net/addr.rs
@@ -623,19 +623,27 @@
         // Fast path: if there's no alignment stuff, write to the output
         // buffer directly
         if f.precision().is_none() && f.width().is_none() {
-            write!(f, "[{}]:{}", self.ip(), self.port())
+            match self.scope_id() {
+                0 => write!(f, "[{}]:{}", self.ip(), self.port()),
+                scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
+            }
         } else {
             const IPV6_SOCKET_BUF_LEN: usize = (4 * 8)  // The address
             + 7  // The colon separators
             + 2  // The brackets
+            + 1 + 10 // The scope id
             + 1 + 5; // The port
 
             let mut buf = [0; IPV6_SOCKET_BUF_LEN];
             let mut buf_slice = &mut buf[..];
 
+            match self.scope_id() {
+                0 => write!(buf_slice, "[{}]:{}", self.ip(), self.port()),
+                scope_id => write!(buf_slice, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
+            }
             // Unwrap is fine because writing to a sufficiently-sized
             // buffer is infallible
-            write!(buf_slice, "[{}]:{}", self.ip(), self.port()).unwrap();
+            .unwrap();
             let len = IPV6_SOCKET_BUF_LEN - buf_slice.len();
 
             // This unsafe is OK because we know what is being written to the buffer
diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/tests.rs
index cee9087..40f5a84 100644
--- a/library/std/src/net/addr/tests.rs
+++ b/library/std/src/net/addr/tests.rs
@@ -68,7 +68,7 @@
     // returns its own address, it is still an error to bind a UDP socket to
     // a non-local address, and so we still get an error here in that case.
 
-    const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300";
+    const INPUT_23076: &str = "1200::AB00:1234::2552:7777:1313:34300";
 
     assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err())
 }
@@ -178,13 +178,21 @@
 
 #[test]
 fn socket_v6_to_str() {
-    let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap();
+    let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0);
 
     assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53");
     assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53    ");
     assert_eq!(format!("{:>24}", socket), "    [2a02:6b8:0:1::1]:53");
     assert_eq!(format!("{:^24}", socket), "  [2a02:6b8:0:1::1]:53  ");
     assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::");
+
+    socket.set_scope_id(5);
+
+    assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1%5]:53  ");
+    assert_eq!(format!("{:>24}", socket), "  [2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1%5]:53 ");
+    assert_eq!(format!("{:.18}", socket), "[2a02:6b8:0:1::1%5");
 }
 
 #[test]
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index f01a7b7..8089d7a 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -456,10 +456,7 @@
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
     #[stable(since = "1.7.0", feature = "ip_17")]
     pub const fn is_link_local(&self) -> bool {
-        match self.octets() {
-            [169, 254, ..] => true,
-            _ => false,
-        }
+        matches!(self.octets(), [169, 254, ..])
     }
 
     /// Returns [`true`] if the address appears to be globally routable.
@@ -1262,10 +1259,7 @@
     /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
     pub const fn is_unicast_link_local_strict(&self) -> bool {
-        (self.segments()[0] & 0xffff) == 0xfe80
-            && (self.segments()[1] & 0xffff) == 0
-            && (self.segments()[2] & 0xffff) == 0
-            && (self.segments()[3] & 0xffff) == 0
+        matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
     }
 
     /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs
index 0570a7c..e8b8962 100644
--- a/library/std/src/net/parser.rs
+++ b/library/std/src/net/parser.rs
@@ -6,11 +6,34 @@
 #[cfg(test)]
 mod tests;
 
+use crate::convert::TryInto as _;
 use crate::error::Error;
 use crate::fmt;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
 use crate::str::FromStr;
 
+trait ReadNumberHelper: crate::marker::Sized {
+    const ZERO: Self;
+    fn checked_mul(&self, other: u32) -> Option<Self>;
+    fn checked_add(&self, other: u32) -> Option<Self>;
+}
+
+macro_rules! impl_helper {
+    ($($t:ty)*) => ($(impl ReadNumberHelper for $t {
+        const ZERO: Self = 0;
+        #[inline]
+        fn checked_mul(&self, other: u32) -> Option<Self> {
+            Self::checked_mul(*self, other.try_into().ok()?)
+        }
+        #[inline]
+        fn checked_add(&self, other: u32) -> Option<Self> {
+            Self::checked_add(*self, other.try_into().ok()?)
+        }
+    })*)
+}
+
+impl_helper! { u8 u16 u32 }
+
 struct Parser<'a> {
     // parsing as ASCII, so can use byte array
     state: &'a [u8],
@@ -21,10 +44,6 @@
         Parser { state: input.as_bytes() }
     }
 
-    fn is_eof(&self) -> bool {
-        self.state.is_empty()
-    }
-
     /// Run a parser, and restore the pre-parse state if it fails
     fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
     where
@@ -40,32 +59,28 @@
 
     /// Run a parser, but fail if the entire input wasn't consumed.
     /// Doesn't run atomically.
-    fn read_till_eof<T, F>(&mut self, inner: F) -> Option<T>
-    where
-        F: FnOnce(&mut Parser<'_>) -> Option<T>,
-    {
-        inner(self).filter(|_| self.is_eof())
-    }
-
-    /// Same as read_till_eof, but returns a Result<AddrParseError> on failure
     fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
     where
         F: FnOnce(&mut Parser<'_>) -> Option<T>,
     {
-        self.read_till_eof(inner).ok_or(AddrParseError(()))
+        let result = inner(self);
+        if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
     }
 
     /// Read the next character from the input
     fn read_char(&mut self) -> Option<char> {
         self.state.split_first().map(|(&b, tail)| {
             self.state = tail;
-            b as char
+            char::from(b)
         })
     }
 
-    /// Read the next character from the input if it matches the target
-    fn read_given_char(&mut self, target: char) -> Option<char> {
-        self.read_atomically(|p| p.read_char().filter(|&c| c == target))
+    #[must_use]
+    /// Read the next character from the input if it matches the target.
+    fn read_given_char(&mut self, target: char) -> Option<()> {
+        self.read_atomically(|p| {
+            p.read_char().and_then(|c| if c == target { Some(()) } else { None })
+        })
     }
 
     /// Helper for reading separators in an indexed loop. Reads the separator
@@ -78,31 +93,32 @@
     {
         self.read_atomically(move |p| {
             if index > 0 {
-                let _ = p.read_given_char(sep)?;
+                p.read_given_char(sep)?;
             }
             inner(p)
         })
     }
 
-    // Read a single digit in the given radix. For instance, 0-9 in radix 10;
-    // 0-9A-F in radix 16.
-    fn read_digit(&mut self, radix: u32) -> Option<u32> {
-        self.read_atomically(move |p| p.read_char()?.to_digit(radix))
-    }
-
     // Read a number off the front of the input in the given radix, stopping
     // at the first non-digit character or eof. Fails if the number has more
-    // digits than max_digits, or the value is >= upto, or if there is no number.
-    fn read_number(&mut self, radix: u32, max_digits: u32, upto: u32) -> Option<u32> {
+    // digits than max_digits or if there is no number.
+    fn read_number<T: ReadNumberHelper>(
+        &mut self,
+        radix: u32,
+        max_digits: Option<usize>,
+    ) -> Option<T> {
         self.read_atomically(move |p| {
-            let mut result = 0;
+            let mut result = T::ZERO;
             let mut digit_count = 0;
 
-            while let Some(digit) = p.read_digit(radix) {
-                result = (result * radix) + digit;
+            while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
+                result = result.checked_mul(radix)?;
+                result = result.checked_add(digit)?;
                 digit_count += 1;
-                if digit_count > max_digits || result >= upto {
-                    return None;
+                if let Some(max_digits) = max_digits {
+                    if digit_count > max_digits {
+                        return None;
+                    }
                 }
             }
 
@@ -116,7 +132,7 @@
             let mut groups = [0; 4];
 
             for (i, slot) in groups.iter_mut().enumerate() {
-                *slot = p.read_separator('.', i, |p| p.read_number(10, 3, 0x100))? as u8;
+                *slot = p.read_separator('.', i, |p| p.read_number(10, None))?;
             }
 
             Some(groups.into())
@@ -140,17 +156,17 @@
                     let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());
 
                     if let Some(v4_addr) = ipv4 {
-                        let octets = v4_addr.octets();
-                        groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
-                        groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
+                        let [one, two, three, four] = v4_addr.octets();
+                        groups[i + 0] = u16::from_be_bytes([one, two]);
+                        groups[i + 1] = u16::from_be_bytes([three, four]);
                         return (i + 2, true);
                     }
                 }
 
-                let group = p.read_separator(':', i, |p| p.read_number(16, 4, 0x10000));
+                let group = p.read_separator(':', i, |p| p.read_number(16, Some(4)));
 
                 match group {
-                    Some(g) => *slot = g as u16,
+                    Some(g) => *slot = g,
                     None => return (i, false),
                 }
             }
@@ -174,8 +190,8 @@
 
             // read `::` if previous code parsed less than 8 groups
             // `::` indicates one or more groups of 16 bits of zeros
-            let _ = p.read_given_char(':')?;
-            let _ = p.read_given_char(':')?;
+            p.read_given_char(':')?;
+            p.read_given_char(':')?;
 
             // Read the back part of the address. The :: must contain at least one
             // set of zeroes, so our max length is 7.
@@ -195,12 +211,19 @@
         self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6))
     }
 
-    /// Read a : followed by a port in base 10
+    /// Read a : followed by a port in base 10.
     fn read_port(&mut self) -> Option<u16> {
         self.read_atomically(|p| {
-            let _ = p.read_given_char(':')?;
-            let port = p.read_number(10, 5, 0x10000)?;
-            Some(port as u16)
+            p.read_given_char(':')?;
+            p.read_number(10, None)
+        })
+    }
+
+    /// Read a % followed by a scope id in base 10.
+    fn read_scope_id(&mut self) -> Option<u32> {
+        self.read_atomically(|p| {
+            p.read_given_char('%')?;
+            p.read_number(10, None)
         })
     }
 
@@ -216,12 +239,13 @@
     /// Read an IPV6 address with a port
     fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> {
         self.read_atomically(|p| {
-            let _ = p.read_given_char('[')?;
+            p.read_given_char('[')?;
             let ip = p.read_ipv6_addr()?;
-            let _ = p.read_given_char(']')?;
+            let scope_id = p.read_scope_id().unwrap_or(0);
+            p.read_given_char(']')?;
 
             let port = p.read_port()?;
-            Some(SocketAddrV6::new(ip, port, 0, 0))
+            Some(SocketAddrV6::new(ip, port, 0, scope_id))
         })
     }
 
diff --git a/library/std/src/net/parser/tests.rs b/library/std/src/net/parser/tests.rs
index ecf5a78..8d8889c 100644
--- a/library/std/src/net/parser/tests.rs
+++ b/library/std/src/net/parser/tests.rs
@@ -3,6 +3,7 @@
 use crate::str::FromStr;
 
 const PORT: u16 = 8080;
+const SCOPE_ID: u32 = 1337;
 
 const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
 const IPV4_STR: &str = "192.168.0.1";
@@ -13,6 +14,7 @@
 const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
 const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
 const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
+const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080";
 
 #[test]
 fn parse_ipv4() {
@@ -74,8 +76,8 @@
 
 #[test]
 fn parse_socket_v6() {
-    let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap();
-    assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0));
+    assert_eq!(IPV6_STR_PORT.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, 0)));
+    assert_eq!(IPV6_STR_PORT_SCOPE_ID.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, SCOPE_ID)));
 
     assert!(SocketAddrV6::from_str(IPV4_STR).is_err());
     assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err());
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index 658369f..fbed3d3 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -152,19 +152,13 @@
         let (done, rx) = channel();
         let tx2 = tx.clone();
         let _t = thread::spawn(move || {
-            match sock3.send_to(&[1], &addr2) {
-                Ok(..) => {
-                    let _ = tx2.send(());
-                }
-                Err(..) => {}
+            if sock3.send_to(&[1], &addr2).is_ok() {
+                let _ = tx2.send(());
             }
             done.send(()).unwrap();
         });
-        match sock1.send_to(&[2], &addr2) {
-            Ok(..) => {
-                let _ = tx.send(());
-            }
-            Err(..) => {}
+        if sock1.send_to(&[2], &addr2).is_ok() {
+            let _ = tx.send(());
         }
         drop(tx);
 
diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs
index ff23c3d..9b7af97 100644
--- a/library/std/src/os/linux/fs.rs
+++ b/library/std/src/os/linux/fs.rs
@@ -20,7 +20,7 @@
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     ///
-    /// [`stat`]: crate::os::linux::raw::stat
+    /// [`stat`]: struct@crate::os::linux::raw::stat
     ///
     /// # Examples
     ///
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
index 4ff3a6e..617c409 100644
--- a/library/std/src/os/linux/raw.rs
+++ b/library/std/src/os/linux/raw.rs
@@ -29,6 +29,7 @@
     target_arch = "x86",
     target_arch = "le32",
     target_arch = "powerpc",
+    target_arch = "sparc",
     target_arch = "arm",
     target_arch = "asmjs",
     target_arch = "wasm32"
diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs
index 5a7e5bc..77e6238 100644
--- a/library/std/src/os/vxworks/fs.rs
+++ b/library/std/src/os/vxworks/fs.rs
@@ -26,10 +26,16 @@
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_atime(&self) -> i64;
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_mtime(&self) -> i64;
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_ctime(&self) -> i64;
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime_nsec(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_blksize(&self) -> u64;
     #[stable(feature = "metadata_ext2", since = "1.8.0")]
     fn st_blocks(&self) -> u64;
@@ -66,12 +72,21 @@
     fn st_atime(&self) -> i64 {
         self.as_inner().as_inner().st_atime as i64
     }
+    fn st_atime_nsec(&self) -> i64 {
+        0
+    }
     fn st_mtime(&self) -> i64 {
         self.as_inner().as_inner().st_mtime as i64
     }
+    fn st_mtime_nsec(&self) -> i64 {
+        0
+    }
     fn st_ctime(&self) -> i64 {
         self.as_inner().as_inner().st_ctime as i64
     }
+    fn st_ctime_nsec(&self) -> i64 {
+        0
+    }
     fn st_blksize(&self) -> u64 {
         self.as_inner().as_inner().st_blksize as u64
     }
diff --git a/library/std/src/os/vxworks/raw.rs b/library/std/src/os/vxworks/raw.rs
index 29a0af5..cb41ddf 100644
--- a/library/std/src/os/vxworks/raw.rs
+++ b/library/std/src/os/vxworks/raw.rs
@@ -5,3 +5,6 @@
 
 #[stable(feature = "pthread_t", since = "1.8.0")]
 pub type pthread_t = c_ulong;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, time_t};
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 18d9c2f..42818673 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -411,3 +411,6 @@
 pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
     panicking::rust_panic_without_hook(payload)
 }
+
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/panic/tests.rs b/library/std/src/panic/tests.rs
new file mode 100644
index 0000000..b37d740
--- /dev/null
+++ b/library/std/src/panic/tests.rs
@@ -0,0 +1,56 @@
+#![allow(dead_code)]
+
+use crate::cell::RefCell;
+use crate::panic::{AssertUnwindSafe, UnwindSafe};
+use crate::rc::Rc;
+use crate::sync::{Arc, Mutex, RwLock};
+
+struct Foo {
+    a: i32,
+}
+
+fn assert<T: UnwindSafe + ?Sized>() {}
+
+#[test]
+fn panic_safety_traits() {
+    assert::<i32>();
+    assert::<&i32>();
+    assert::<*mut i32>();
+    assert::<*const i32>();
+    assert::<usize>();
+    assert::<str>();
+    assert::<&str>();
+    assert::<Foo>();
+    assert::<&Foo>();
+    assert::<Vec<i32>>();
+    assert::<String>();
+    assert::<RefCell<i32>>();
+    assert::<Box<i32>>();
+    assert::<Mutex<i32>>();
+    assert::<RwLock<i32>>();
+    assert::<&Mutex<i32>>();
+    assert::<&RwLock<i32>>();
+    assert::<Rc<i32>>();
+    assert::<Arc<i32>>();
+    assert::<Box<[u8]>>();
+
+    {
+        trait Trait: UnwindSafe {}
+        assert::<Box<dyn Trait>>();
+    }
+
+    fn bar<T>() {
+        assert::<Mutex<T>>();
+        assert::<RwLock<T>>();
+    }
+
+    fn baz<T: UnwindSafe>() {
+        assert::<Box<T>>();
+        assert::<Vec<T>>();
+        assert::<RefCell<T>>();
+        assert::<AssertUnwindSafe<T>>();
+        assert::<&AssertUnwindSafe<T>>();
+        assert::<Rc<AssertUnwindSafe<T>>>();
+        assert::<Arc<AssertUnwindSafe<T>>>();
+    }
+}
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index b83c1e9..50bd2a0 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1009,7 +1009,7 @@
 /// [`set_extension`]: PathBuf::set_extension
 ///
 /// More details about the overall approach can be found in
-/// the [module documentation](index.html).
+/// the [module documentation](self).
 ///
 /// # Examples
 ///
@@ -1655,7 +1655,7 @@
 /// see [`PathBuf`].
 ///
 /// More details about the overall approach can be found in
-/// the [module documentation](index.html).
+/// the [module documentation](self).
 ///
 /// # Examples
 ///
@@ -1838,7 +1838,7 @@
             // FIXME: Allow Redox prefixes
             self.has_root() || has_redox_scheme(self.as_u8_slice())
         } else {
-            self.has_root() && (cfg!(unix) || self.prefix().is_some())
+            self.has_root() && (cfg!(any(unix, target_os = "wasi")) || self.prefix().is_some())
         }
     }
 
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 81bbf37..ae67847 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -1118,6 +1118,8 @@
 /// For more information and a list of supported ABIs, see [the nomicon's
 /// section on foreign calling conventions][nomicon-abi].
 ///
+/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
+///
 /// ### Variadic functions
 ///
 /// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 9f3796e..a149946 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -110,6 +110,8 @@
 use crate::str;
 use crate::sys::pipe::{read2, AnonPipe};
 use crate::sys::process as imp;
+#[unstable(feature = "command_access", issue = "44434")]
+pub use crate::sys_common::process::CommandEnvs;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 /// Representation of a running or exited child process.
@@ -894,6 +896,98 @@
             .map(Child::from_inner)
             .and_then(|mut p| p.wait())
     }
+
+    /// Returns the path to the program that was given to [`Command::new`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(command_access)]
+    /// use std::process::Command;
+    ///
+    /// let cmd = Command::new("echo");
+    /// assert_eq!(cmd.get_program(), "echo");
+    /// ```
+    #[unstable(feature = "command_access", issue = "44434")]
+    pub fn get_program(&self) -> &OsStr {
+        self.inner.get_program()
+    }
+
+    /// Returns an iterator of the arguments that will be passed to the program.
+    ///
+    /// This does not include the path to the program as the first argument;
+    /// it only includes the arguments specified with [`Command::arg`] and
+    /// [`Command::args`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(command_access)]
+    /// use std::ffi::OsStr;
+    /// use std::process::Command;
+    ///
+    /// let mut cmd = Command::new("echo");
+    /// cmd.arg("first").arg("second");
+    /// let args: Vec<&OsStr> = cmd.get_args().collect();
+    /// assert_eq!(args, &["first", "second"]);
+    /// ```
+    #[unstable(feature = "command_access", issue = "44434")]
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        CommandArgs { inner: self.inner.get_args() }
+    }
+
+    /// Returns an iterator of the environment variables that will be set when
+    /// the process is spawned.
+    ///
+    /// Each element is a tuple `(&OsStr, Option<&OsStr>)`, where the first
+    /// value is the key, and the second is the value, which is [`None`] if
+    /// the environment variable is to be explicitly removed.
+    ///
+    /// This only includes environment variables explicitly set with
+    /// [`Command::env`], [`Command::envs`], and [`Command::env_remove`]. It
+    /// does not include environment variables that will be inherited by the
+    /// child process.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(command_access)]
+    /// use std::ffi::OsStr;
+    /// use std::process::Command;
+    ///
+    /// let mut cmd = Command::new("ls");
+    /// cmd.env("TERM", "dumb").env_remove("TZ");
+    /// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect();
+    /// assert_eq!(envs, &[
+    ///     (OsStr::new("TERM"), Some(OsStr::new("dumb"))),
+    ///     (OsStr::new("TZ"), None)
+    /// ]);
+    /// ```
+    #[unstable(feature = "command_access", issue = "44434")]
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        self.inner.get_envs()
+    }
+
+    /// Returns the working directory for the child process.
+    ///
+    /// This returns [`None`] if the working directory will not be changed.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(command_access)]
+    /// use std::path::Path;
+    /// use std::process::Command;
+    ///
+    /// let mut cmd = Command::new("ls");
+    /// assert_eq!(cmd.get_current_dir(), None);
+    /// cmd.current_dir("/bin");
+    /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin")));
+    /// ```
+    #[unstable(feature = "command_access", issue = "44434")]
+    pub fn get_current_dir(&self) -> Option<&Path> {
+        self.inner.get_current_dir()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -918,6 +1012,37 @@
     }
 }
 
+/// An iterator over the command arguments.
+///
+/// This struct is created by [`Command::get_args`]. See its documentation for
+/// more.
+#[unstable(feature = "command_access", issue = "44434")]
+#[derive(Debug)]
+pub struct CommandArgs<'a> {
+    inner: imp::CommandArgs<'a>,
+}
+
+#[unstable(feature = "command_access", issue = "44434")]
+impl<'a> Iterator for CommandArgs<'a> {
+    type Item = &'a OsStr;
+    fn next(&mut self) -> Option<&'a OsStr> {
+        self.inner.next()
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+#[unstable(feature = "command_access", issue = "44434")]
+impl<'a> ExactSizeIterator for CommandArgs<'a> {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+    fn is_empty(&self) -> bool {
+        self.inner.is_empty()
+    }
+}
+
 /// The output of a finished process.
 ///
 /// This is returned in a Result by either the [`output`] method of a
@@ -1059,7 +1184,7 @@
     }
 
     /// This stream will be ignored. This is the equivalent of attaching the
-    /// stream to `/dev/null`
+    /// stream to `/dev/null`.
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs
index 7e2155d..ffc1e57 100644
--- a/library/std/src/sync/condvar.rs
+++ b/library/std/src/sync/condvar.rs
@@ -2,10 +2,8 @@
 mod tests;
 
 use crate::fmt;
-use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sync::{mutex, MutexGuard, PoisonError};
 use crate::sys_common::condvar as sys;
-use crate::sys_common::mutex as sys_mutex;
 use crate::sys_common::poison::{self, LockResult};
 use crate::time::{Duration, Instant};
 
@@ -109,8 +107,7 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Condvar {
-    inner: Box<sys::Condvar>,
-    mutex: AtomicUsize,
+    inner: sys::Condvar,
 }
 
 impl Condvar {
@@ -126,11 +123,7 @@
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new() -> Condvar {
-        let mut c = Condvar { inner: box sys::Condvar::new(), mutex: AtomicUsize::new(0) };
-        unsafe {
-            c.inner.init();
-        }
-        c
+        Condvar { inner: sys::Condvar::new() }
     }
 
     /// Blocks the current thread until this condition variable receives a
@@ -192,7 +185,6 @@
     pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
         let poisoned = unsafe {
             let lock = mutex::guard_lock(&guard);
-            self.verify(lock);
             self.inner.wait(lock);
             mutex::guard_poison(&guard).get()
         };
@@ -389,7 +381,6 @@
     ) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
         let (poisoned, result) = unsafe {
             let lock = mutex::guard_lock(&guard);
-            self.verify(lock);
             let success = self.inner.wait_timeout(lock, dur);
             (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
         };
@@ -510,7 +501,7 @@
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn notify_one(&self) {
-        unsafe { self.inner.notify_one() }
+        self.inner.notify_one()
     }
 
     /// Wakes up all blocked threads on this condvar.
@@ -550,27 +541,7 @@
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn notify_all(&self) {
-        unsafe { self.inner.notify_all() }
-    }
-
-    fn verify(&self, mutex: &sys_mutex::Mutex) {
-        let addr = mutex as *const _ as usize;
-        match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
-            // If we got out 0, then we have successfully bound the mutex to
-            // this cvar.
-            0 => {}
-
-            // If we get out a value that's the same as `addr`, then someone
-            // already beat us to the punch.
-            n if n == addr => {}
-
-            // Anything else and we're using more than one mutex on this cvar,
-            // which is currently disallowed.
-            _ => panic!(
-                "attempted to use a condition variable with two \
-                         mutexes"
-            ),
-        }
+        self.inner.notify_all()
     }
 }
 
@@ -588,10 +559,3 @@
         Condvar::new()
     }
 }
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Drop for Condvar {
-    fn drop(&mut self) {
-        unsafe { self.inner.destroy() }
-    }
-}
diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs
index 86d099e..6757707 100644
--- a/library/std/src/sync/condvar/tests.rs
+++ b/library/std/src/sync/condvar/tests.rs
@@ -191,7 +191,7 @@
 
 #[test]
 #[should_panic]
-#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(not(unix), ignore)]
 fn two_mutexes() {
     let m = Arc::new(Mutex::new(()));
     let m2 = m.clone();
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index a1703c7..a01ebb3 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -166,12 +166,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")]
 pub struct Mutex<T: ?Sized> {
-    // Note that this mutex is in a *box*, not inlined into the struct itself.
-    // Once a native mutex has been used once, its address can never change (it
-    // can't be moved). This mutex type can be safely moved at any time, so to
-    // ensure that the native mutex is used correctly we box the inner mutex to
-    // give it a constant address.
-    inner: Box<sys::Mutex>,
+    inner: sys::MovableMutex,
     poison: poison::Flag,
     data: UnsafeCell<T>,
 }
@@ -218,15 +213,11 @@
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(t: T) -> Mutex<T> {
-        let mut m = Mutex {
-            inner: box sys::Mutex::new(),
+        Mutex {
+            inner: sys::MovableMutex::new(),
             poison: poison::Flag::new(),
             data: UnsafeCell::new(t),
-        };
-        unsafe {
-            m.inner.init();
         }
-        m
     }
 }
 
@@ -285,7 +276,7 @@
     /// # Errors
     ///
     /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return failure if the mutex would otherwise be
+    /// this call will return an error if the mutex would otherwise be
     /// acquired.
     ///
     /// # Examples
@@ -378,7 +369,6 @@
                 (ptr::read(inner), ptr::read(poison), ptr::read(data))
             };
             mem::forget(self);
-            inner.destroy(); // Keep in sync with the `Drop` impl.
             drop(inner);
 
             poison::map_result(poison.borrow(), |_| data.into_inner())
@@ -411,18 +401,6 @@
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> {
-    fn drop(&mut self) {
-        // This is actually safe b/c we know that there is no further usage of
-        // this mutex (it's up to the user to arrange for a mutex to get
-        // dropped, that's not our job)
-        //
-        // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
-        unsafe { self.inner.destroy() }
-    }
-}
-
 #[stable(feature = "mutex_from", since = "1.24.0")]
 impl<T> From<T> for Mutex<T> {
     /// Creates a new mutex in an unlocked state ready for use.
@@ -509,7 +487,7 @@
     }
 }
 
-pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
+pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex {
     &guard.lock.inner
 }
 
diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs
index dabdc0c..f09bc01 100644
--- a/library/std/src/sys/cloudabi/condvar.rs
+++ b/library/std/src/sys/cloudabi/condvar.rs
@@ -1,4 +1,3 @@
-use crate::cell::UnsafeCell;
 use crate::mem;
 use crate::sync::atomic::{AtomicU32, Ordering};
 use crate::sys::cloudabi::abi;
@@ -12,35 +11,36 @@
 }
 
 pub struct Condvar {
-    condvar: UnsafeCell<AtomicU32>,
+    condvar: AtomicU32,
 }
 
+pub type MovableCondvar = Condvar;
+
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
-const NEW: Condvar =
-    Condvar { condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)) };
-
 impl Condvar {
     pub const fn new() -> Condvar {
-        NEW
+        Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) }
     }
 
     pub unsafe fn init(&mut self) {}
 
     pub unsafe fn notify_one(&self) {
-        let condvar = self.condvar.get();
-        if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
-            let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1);
+        if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+            let ret = abi::condvar_signal(
+                &self.condvar as *const AtomicU32 as *mut abi::condvar,
+                abi::scope::PRIVATE,
+                1,
+            );
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable");
         }
     }
 
     pub unsafe fn notify_all(&self) {
-        let condvar = self.condvar.get();
-        if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+        if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
             let ret = abi::condvar_signal(
-                condvar as *mut abi::condvar,
+                &self.condvar as *const AtomicU32 as *mut abi::condvar,
                 abi::scope::PRIVATE,
                 abi::nthreads::MAX,
             );
@@ -51,20 +51,19 @@
     pub unsafe fn wait(&self, mutex: &Mutex) {
         let mutex = mutex::raw(mutex);
         assert_eq!(
-            (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This lock is not write-locked by this thread"
         );
 
         // Call into the kernel to wait on the condition variable.
-        let condvar = self.condvar.get();
         let subscription = abi::subscription {
             type_: abi::eventtype::CONDVAR,
             union: abi::subscription_union {
                 condvar: abi::subscription_condvar {
-                    condvar: condvar as *mut abi::condvar,
+                    condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
                     condvar_scope: abi::scope::PRIVATE,
-                    lock: mutex as *mut abi::lock,
+                    lock: mutex as *const AtomicU32 as *mut abi::lock,
                     lock_scope: abi::scope::PRIVATE,
                 },
             },
@@ -84,13 +83,12 @@
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         let mutex = mutex::raw(mutex);
         assert_eq!(
-            (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This lock is not write-locked by this thread"
         );
 
         // Call into the kernel to wait on the condition variable.
-        let condvar = self.condvar.get();
         let timeout =
             checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds");
         let subscriptions = [
@@ -98,9 +96,9 @@
                 type_: abi::eventtype::CONDVAR,
                 union: abi::subscription_union {
                     condvar: abi::subscription_condvar {
-                        condvar: condvar as *mut abi::condvar,
+                        condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
                         condvar_scope: abi::scope::PRIVATE,
-                        lock: mutex as *mut abi::lock,
+                        lock: mutex as *const AtomicU32 as *mut abi::lock,
                         lock_scope: abi::scope::PRIVATE,
                     },
                 },
@@ -122,7 +120,7 @@
         let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit();
         let ret = abi::poll(
             subscriptions.as_ptr(),
-            mem::MaybeUninit::first_ptr_mut(&mut events),
+            mem::MaybeUninit::slice_as_mut_ptr(&mut events),
             2,
             nevents.as_mut_ptr(),
         );
@@ -142,9 +140,8 @@
     }
 
     pub unsafe fn destroy(&self) {
-        let condvar = self.condvar.get();
         assert_eq!(
-            (*condvar).load(Ordering::Relaxed),
+            self.condvar.load(Ordering::Relaxed),
             abi::CONDVAR_HAS_NO_WAITERS.0,
             "Attempted to destroy a condition variable with blocked threads"
         );
diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs
index 580ab0e..1203d8d 100644
--- a/library/std/src/sys/cloudabi/mutex.rs
+++ b/library/std/src/sys/cloudabi/mutex.rs
@@ -1,4 +1,4 @@
-use crate::cell::UnsafeCell;
+use crate::cell::Cell;
 use crate::mem;
 use crate::mem::MaybeUninit;
 use crate::sync::atomic::{AtomicU32, Ordering};
@@ -15,7 +15,9 @@
 // implemented identically.
 pub struct Mutex(RWLock);
 
-pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
+pub type MovableMutex = Mutex;
+
+pub unsafe fn raw(m: &Mutex) -> &AtomicU32 {
     rwlock::raw(&m.0)
 }
 
@@ -48,28 +50,23 @@
 }
 
 pub struct ReentrantMutex {
-    lock: UnsafeCell<MaybeUninit<AtomicU32>>,
-    recursion: UnsafeCell<MaybeUninit<u32>>,
+    lock: AtomicU32,
+    recursion: Cell<u32>,
 }
 
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
 impl ReentrantMutex {
     pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex {
-            lock: UnsafeCell::new(MaybeUninit::uninit()),
-            recursion: UnsafeCell::new(MaybeUninit::uninit()),
-        }
+        ReentrantMutex { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), recursion: Cell::new(0) }
     }
 
-    pub unsafe fn init(&self) {
-        *self.lock.get() = MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0));
-        *self.recursion.get() = MaybeUninit::new(0);
-    }
+    pub unsafe fn init(&self) {}
 
     pub unsafe fn try_lock(&self) -> bool {
         // Attempt to acquire the lock.
-        let lock = (*self.lock.get()).as_mut_ptr();
-        let recursion = (*self.recursion.get()).as_mut_ptr();
-        if let Err(old) = (*lock).compare_exchange(
+        if let Err(old) = self.lock.compare_exchange(
             abi::LOCK_UNLOCKED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             Ordering::Acquire,
@@ -78,14 +75,14 @@
             // If we fail to acquire the lock, it may be the case
             // that we've already acquired it and may need to recurse.
             if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 {
-                *recursion += 1;
+                self.recursion.set(self.recursion.get() + 1);
                 true
             } else {
                 false
             }
         } else {
             // Success.
-            assert_eq!(*recursion, 0, "Mutex has invalid recursion count");
+            assert_eq!(self.recursion.get(), 0, "Mutex has invalid recursion count");
             true
         }
     }
@@ -93,7 +90,7 @@
     pub unsafe fn lock(&self) {
         if !self.try_lock() {
             // Call into the kernel to acquire a write lock.
-            let lock = self.lock.get();
+            let lock = &self.lock as *const AtomicU32;
             let subscription = abi::subscription {
                 type_: abi::eventtype::LOCK_WRLOCK,
                 union: abi::subscription_union {
@@ -114,17 +111,17 @@
     }
 
     pub unsafe fn unlock(&self) {
-        let lock = (*self.lock.get()).as_mut_ptr();
-        let recursion = (*self.recursion.get()).as_mut_ptr();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This mutex is locked by a different thread"
         );
 
-        if *recursion > 0 {
-            *recursion -= 1;
-        } else if !(*lock)
+        let r = self.recursion.get();
+        if r > 0 {
+            self.recursion.set(r - 1);
+        } else if !self
+            .lock
             .compare_exchange(
                 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
                 abi::LOCK_UNLOCKED.0,
@@ -135,19 +132,20 @@
         {
             // Lock is managed by kernelspace. Call into the kernel
             // to unblock waiting threads.
-            let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+            let ret = abi::lock_unlock(
+                &self.lock as *const AtomicU32 as *mut abi::lock,
+                abi::scope::PRIVATE,
+            );
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex");
         }
     }
 
     pub unsafe fn destroy(&self) {
-        let lock = (*self.lock.get()).as_mut_ptr();
-        let recursion = (*self.recursion.get()).as_mut_ptr();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed),
+            self.lock.load(Ordering::Relaxed),
             abi::LOCK_UNLOCKED.0,
             "Attempted to destroy locked mutex"
         );
-        assert_eq!(*recursion, 0, "Recursion counter invalid");
+        assert_eq!(self.recursion.get(), 0, "Recursion counter invalid");
     }
 }
diff --git a/library/std/src/sys/cloudabi/rwlock.rs b/library/std/src/sys/cloudabi/rwlock.rs
index b8af5af..508de8b 100644
--- a/library/std/src/sys/cloudabi/rwlock.rs
+++ b/library/std/src/sys/cloudabi/rwlock.rs
@@ -1,4 +1,3 @@
-use crate::cell::UnsafeCell;
 use crate::mem;
 use crate::mem::MaybeUninit;
 use crate::sync::atomic::{AtomicU32, Ordering};
@@ -13,28 +12,25 @@
 static mut RDLOCKS_ACQUIRED: u32 = 0;
 
 pub struct RWLock {
-    lock: UnsafeCell<AtomicU32>,
+    lock: AtomicU32,
 }
 
-pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 {
-    r.lock.get()
+pub unsafe fn raw(r: &RWLock) -> &AtomicU32 {
+    &r.lock
 }
 
 unsafe impl Send for RWLock {}
 unsafe impl Sync for RWLock {}
 
-const NEW: RWLock = RWLock { lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)) };
-
 impl RWLock {
     pub const fn new() -> RWLock {
-        NEW
+        RWLock { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0) }
     }
 
     pub unsafe fn try_read(&self) -> bool {
-        let lock = self.lock.get();
         let mut old = abi::LOCK_UNLOCKED.0;
         while let Err(cur) =
-            (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
+            self.lock.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
         {
             if (cur & abi::LOCK_WRLOCKED.0) != 0 {
                 // Another thread already has a write lock.
@@ -61,12 +57,11 @@
     pub unsafe fn read(&self) {
         if !self.try_read() {
             // Call into the kernel to acquire a read lock.
-            let lock = self.lock.get();
             let subscription = abi::subscription {
                 type_: abi::eventtype::LOCK_RDLOCK,
                 union: abi::subscription_union {
                     lock: abi::subscription_lock {
-                        lock: lock as *mut abi::lock,
+                        lock: &self.lock as *const AtomicU32 as *mut abi::lock,
                         lock_scope: abi::scope::PRIVATE,
                     },
                 },
@@ -96,11 +91,10 @@
         assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count");
         let mut old = 1;
         loop {
-            let lock = self.lock.get();
             if old == 1 | abi::LOCK_KERNEL_MANAGED.0 {
                 // Last read lock while threads are waiting. Attempt to upgrade
                 // to a write lock before calling into the kernel to unlock.
-                if let Err(cur) = (*lock).compare_exchange_weak(
+                if let Err(cur) = self.lock.compare_exchange_weak(
                     old,
                     __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0,
                     Ordering::Acquire,
@@ -109,7 +103,10 @@
                     old = cur;
                 } else {
                     // Call into the kernel to unlock.
-                    let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+                    let ret = abi::lock_unlock(
+                        &self.lock as *const AtomicU32 as *mut abi::lock,
+                        abi::scope::PRIVATE,
+                    );
                     assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
                     break;
                 }
@@ -122,7 +119,7 @@
                     0,
                     "Attempted to read-unlock a write-locked rwlock"
                 );
-                if let Err(cur) = (*lock).compare_exchange_weak(
+                if let Err(cur) = self.lock.compare_exchange_weak(
                     old,
                     old - 1,
                     Ordering::Acquire,
@@ -140,8 +137,7 @@
 
     pub unsafe fn try_write(&self) -> bool {
         // Attempt to acquire the lock.
-        let lock = self.lock.get();
-        if let Err(old) = (*lock).compare_exchange(
+        if let Err(old) = self.lock.compare_exchange(
             abi::LOCK_UNLOCKED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             Ordering::Acquire,
@@ -163,12 +159,11 @@
     pub unsafe fn write(&self) {
         if !self.try_write() {
             // Call into the kernel to acquire a write lock.
-            let lock = self.lock.get();
             let subscription = abi::subscription {
                 type_: abi::eventtype::LOCK_WRLOCK,
                 union: abi::subscription_union {
                     lock: abi::subscription_lock {
-                        lock: lock as *mut abi::lock,
+                        lock: &self.lock as *const AtomicU32 as *mut abi::lock,
                         lock_scope: abi::scope::PRIVATE,
                     },
                 },
@@ -184,14 +179,14 @@
     }
 
     pub unsafe fn write_unlock(&self) {
-        let lock = self.lock.get();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This rwlock is not write-locked by this thread"
         );
 
-        if !(*lock)
+        if !self
+            .lock
             .compare_exchange(
                 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
                 abi::LOCK_UNLOCKED.0,
@@ -202,15 +197,17 @@
         {
             // Lock is managed by kernelspace. Call into the kernel
             // to unblock waiting threads.
-            let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+            let ret = abi::lock_unlock(
+                &self.lock as *const AtomicU32 as *mut abi::lock,
+                abi::scope::PRIVATE,
+            );
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
         }
     }
 
     pub unsafe fn destroy(&self) {
-        let lock = self.lock.get();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed),
+            self.lock.load(Ordering::Relaxed),
             abi::LOCK_UNLOCKED.0,
             "Attempted to destroy locked rwlock"
         );
diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs
index 72c1b85..7727293 100644
--- a/library/std/src/sys/hermit/args.rs
+++ b/library/std/src/sys/hermit/args.rs
@@ -57,11 +57,11 @@
     use crate::ptr;
     use crate::sys_common::os_str_bytes::*;
 
-    use crate::sys_common::mutex::Mutex;
+    use crate::sys_common::mutex::StaticMutex;
 
     static mut ARGC: isize = 0;
     static mut ARGV: *const *const u8 = ptr::null();
-    static LOCK: Mutex = Mutex::new();
+    static LOCK: StaticMutex = StaticMutex::new();
 
     pub unsafe fn init(argc: isize, argv: *const *const u8) {
         let _guard = LOCK.lock();
diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs
index 52c8c3b..b45e871 100644
--- a/library/std/src/sys/hermit/condvar.rs
+++ b/library/std/src/sys/hermit/condvar.rs
@@ -14,6 +14,8 @@
     sem2: *const c_void,
 }
 
+pub type MovableCondvar = Box<Condvar>;
+
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs
index 57fd7ef..ffa234f 100644
--- a/library/std/src/sys/sgx/abi/mem.rs
+++ b/library/std/src/sys/sgx/abi/mem.rs
@@ -21,8 +21,15 @@
 #[inline(always)]
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub fn image_base() -> u64 {
-    let base;
-    unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) };
+    let base: u64;
+    unsafe {
+        asm!(
+            "lea IMAGE_BASE(%rip), {}",
+            lateout(reg) base,
+            // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9.
+            options(att_syntax, nostack, preserves_flags, nomem, pure),
+        )
+    };
     base
 }
 
diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs
index b0693b63..a0eb12c 100644
--- a/library/std/src/sys/sgx/abi/mod.rs
+++ b/library/std/src/sys/sgx/abi/mod.rs
@@ -45,7 +45,7 @@
         // We need to wait until the initialization is done.
         BUSY => {
             while RELOC_STATE.load(Ordering::Acquire) == BUSY {
-                core::arch::x86_64::_mm_pause()
+                core::hint::spin_loop();
             }
         }
         // Initialization is done.
diff --git a/library/std/src/sys/sgx/abi/tls.rs b/library/std/src/sys/sgx/abi/tls.rs
index 0d8952b..13d96e9 100644
--- a/library/std/src/sys/sgx/abi/tls.rs
+++ b/library/std/src/sys/sgx/abi/tls.rs
@@ -87,18 +87,21 @@
     }
 
     pub unsafe fn activate(&self) -> ActiveTls<'_> {
-        set_tls_ptr(self as *const Tls as _);
+        // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
+        unsafe { set_tls_ptr(self as *const Tls as _) };
         ActiveTls { tls: self }
     }
 
     #[allow(unused)]
     pub unsafe fn activate_persistent(self: Box<Self>) {
-        set_tls_ptr((&*self) as *const Tls as _);
+        // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
+        unsafe { set_tls_ptr((&*self) as *const Tls as _) };
         mem::forget(self);
     }
 
     unsafe fn current<'a>() -> &'a Tls {
-        &*(get_tls_ptr() as *const Tls)
+        // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
+        unsafe { &*(get_tls_ptr() as *const Tls) }
     }
 
     pub fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
index 76a9b42..9fdb1b4 100644
--- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
@@ -89,9 +89,12 @@
     /// * the pointed-to range is not in user memory.
     unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
         assert!(ptr.wrapping_add(size) >= ptr);
-        let ret = Self::from_raw_sized_unchecked(ptr, size);
-        Self::check_ptr(ret);
-        NonNull::new_unchecked(ret as _)
+        // SAFETY: The caller has guaranteed the pointer is valid
+        let ret = unsafe { Self::from_raw_sized_unchecked(ptr, size) };
+        unsafe {
+            Self::check_ptr(ret);
+            NonNull::new_unchecked(ret as _)
+        }
     }
 
     /// Checks if a pointer may point to `Self` in user memory.
@@ -112,7 +115,7 @@
         let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) };
 
         assert!(is_aligned(ptr as *const u8));
-        assert!(is_user_range(ptr as _, mem::size_of_val(&*ptr)));
+        assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr })));
         assert!(!ptr.is_null());
     }
 }
@@ -135,11 +138,23 @@
         mem::align_of::<T>()
     }
 
+    /// # Safety
+    /// Behavior is undefined if any of these conditions are violated:
+    /// * `ptr` must be [valid] for writes of `size` many bytes, and it must be
+    ///   properly aligned.
+    ///
+    /// [valid]: core::ptr#safety
+    /// # Panics
+    ///
+    /// This function panics if:
+    ///
+    /// * the element size is not a factor of the size
     unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
         let elem_size = mem::size_of::<T>();
         assert_eq!(size % elem_size, 0);
         let len = size / elem_size;
-        slice::from_raw_parts_mut(ptr as _, len)
+        // SAFETY: The caller must uphold the safety contract for `from_raw_sized_unchecked`
+        unsafe { slice::from_raw_parts_mut(ptr as _, len) }
     }
 }
 
@@ -170,13 +185,15 @@
 
 impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
     unsafe fn new_userref(v: *mut T) -> Self {
-        NonNull::new_unchecked(v as _)
+        // SAFETY: The caller has guaranteed the pointer is valid
+        unsafe { NonNull::new_unchecked(v as _) }
     }
 }
 
 impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
     unsafe fn new_userref(v: NonNull<T>) -> Self {
-        NonNull::new_userref(v.as_ptr())
+        // SAFETY: The caller has guaranteed the pointer is valid
+        unsafe { NonNull::new_userref(v.as_ptr()) }
     }
 }
 
@@ -231,8 +248,9 @@
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw(ptr: *mut T) -> Self {
-        T::check_ptr(ptr);
-        User(NonNull::new_userref(ptr))
+        // SAFETY: the caller must uphold the safety contract for `from_raw`.
+        unsafe { T::check_ptr(ptr) };
+        User(unsafe { NonNull::new_userref(ptr) })
     }
 
     /// Converts this value into a raw pointer. The value will no longer be
@@ -280,7 +298,9 @@
     /// * The pointed-to range does not fit in the address space
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
-        User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>())))
+        User(unsafe {
+            NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()))
+        })
     }
 }
 
@@ -301,8 +321,9 @@
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
-        T::check_ptr(ptr);
-        &*(ptr as *const Self)
+        // SAFETY: The caller must uphold the safety contract for `from_ptr`.
+        unsafe { T::check_ptr(ptr) };
+        unsafe { &*(ptr as *const Self) }
     }
 
     /// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct
@@ -318,8 +339,9 @@
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
-        T::check_ptr(ptr);
-        &mut *(ptr as *mut Self)
+        // SAFETY: The caller must uphold the safety contract for `from_mut_ptr`.
+        unsafe { T::check_ptr(ptr) };
+        unsafe { &mut *(ptr as *mut Self) }
     }
 
     /// Copies `val` into user memory.
@@ -394,7 +416,10 @@
     /// * The pointed-to range does not fit in the address space
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
-        &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
+        // SAFETY: The caller must uphold the safety contract for `from_raw_parts`.
+        unsafe {
+            &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
+        }
     }
 
     /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
@@ -412,7 +437,10 @@
     /// * The pointed-to range does not fit in the address space
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
-        &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
+        // SAFETY: The caller must uphold the safety contract for `from_raw_parts_mut`.
+        unsafe {
+            &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
+        }
     }
 
     /// Obtain a raw pointer to the first element of this user slice.
@@ -437,13 +465,12 @@
     /// This function panics if the destination doesn't have the same size as
     /// the source. This can happen for dynamically-sized types such as slices.
     pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
-        unsafe {
-            if let Some(missing) = self.len().checked_sub(dest.capacity()) {
-                dest.reserve(missing)
-            }
-            dest.set_len(self.len());
-            self.copy_to_enclave(&mut dest[..]);
+        if let Some(missing) = self.len().checked_sub(dest.capacity()) {
+            dest.reserve(missing)
         }
+        // SAFETY: We reserve enough space above.
+        unsafe { dest.set_len(self.len()) };
+        self.copy_to_enclave(&mut dest[..]);
     }
 
     /// Copies the value from user memory into a vector in enclave memory.
diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs
index 73f1b95..a6a659d 100644
--- a/library/std/src/sys/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs
@@ -140,7 +140,8 @@
 /// Usercall `launch_thread`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub unsafe fn launch_thread() -> IoResult<()> {
-    raw::launch_thread().from_sgx_result()
+    // SAFETY: The caller must uphold the safety contract for `launch_thread`.
+    unsafe { raw::launch_thread().from_sgx_result() }
 }
 
 /// Usercall `exit`. See the ABI documentation for more information.
diff --git a/library/std/src/sys/sgx/abi/usercalls/raw.rs b/library/std/src/sys/sgx/abi/usercalls/raw.rs
index e0ebf86..b0e6a6a 100644
--- a/library/std/src/sys/sgx/abi/usercalls/raw.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/raw.rs
@@ -33,7 +33,7 @@
     p4: u64,
     abort: bool,
 ) -> (u64, u64) {
-    let UsercallReturn(a, b) = usercall(nr, p1, p2, abort as _, p3, p4);
+    let UsercallReturn(a, b) = unsafe { usercall(nr, p1, p2, abort as _, p3, p4) };
     (a, b)
 }
 
@@ -175,14 +175,14 @@
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                RegisterArgument::into_register($n2),
-                RegisterArgument::into_register($n3),
-                RegisterArgument::into_register($n4),
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    RegisterArgument::into_register($n2),
+                    RegisterArgument::into_register($n3),
+                    RegisterArgument::into_register($n4),
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => (
@@ -191,14 +191,14 @@
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                RegisterArgument::into_register($n2),
-                RegisterArgument::into_register($n3),
-                0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    RegisterArgument::into_register($n2),
+                    RegisterArgument::into_register($n3),
+                    0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => (
@@ -207,13 +207,13 @@
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                RegisterArgument::into_register($n2),
-                0,0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    RegisterArgument::into_register($n2),
+                    0,0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => (
@@ -222,12 +222,12 @@
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                0,0,0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    0,0,0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident() -> $r:tt) => (
@@ -236,11 +236,11 @@
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f() -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                0,0,0,0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    0,0,0,0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($($n:ident: $t:ty),*)) => (
diff --git a/library/std/src/sys/sgx/alloc.rs b/library/std/src/sys/sgx/alloc.rs
index 40daec75..4559ea7 100644
--- a/library/std/src/sys/sgx/alloc.rs
+++ b/library/std/src/sys/sgx/alloc.rs
@@ -4,6 +4,10 @@
 
 // Using a SpinMutex because we never want to exit the enclave waiting for the
 // allocator.
+//
+// The current allocator here is the `dlmalloc` crate which we've got included
+// in the rust-lang/rust repository as a submodule. The crate is a port of
+// dlmalloc.c from C to Rust.
 #[cfg_attr(test, linkage = "available_externally")]
 #[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"]
 static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALLOC_INIT);
@@ -12,22 +16,26 @@
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        DLMALLOC.lock().malloc(layout.size(), layout.align())
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().malloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        DLMALLOC.lock().calloc(layout.size(), layout.align())
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().calloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        DLMALLOC.lock().free(ptr, layout.size(), layout.align())
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().free(ptr, layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size)
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) }
     }
 }
 
@@ -36,11 +44,11 @@
 #[cfg(not(test))]
 #[no_mangle]
 pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
-    crate::alloc::alloc(Layout::from_size_align_unchecked(size, align))
+    unsafe { crate::alloc::alloc(Layout::from_size_align_unchecked(size, align)) }
 }
 
 #[cfg(not(test))]
 #[no_mangle]
 pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
-    crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+    unsafe { crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
 }
diff --git a/library/std/src/sys/sgx/args.rs b/library/std/src/sys/sgx/args.rs
index 5a53695..2d2e692 100644
--- a/library/std/src/sys/sgx/args.rs
+++ b/library/std/src/sys/sgx/args.rs
@@ -13,7 +13,7 @@
 #[cfg_attr(test, allow(dead_code))]
 pub unsafe fn init(argc: isize, argv: *const *const u8) {
     if argc != 0 {
-        let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _);
+        let args = unsafe { alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _) };
         let args = args
             .iter()
             .map(|a| OsString::from_inner(Buf { inner: a.copy_user_buffer() }))
diff --git a/library/std/src/sys/sgx/condvar.rs b/library/std/src/sys/sgx/condvar.rs
index ed6dbcf..55ac052 100644
--- a/library/std/src/sys/sgx/condvar.rs
+++ b/library/std/src/sys/sgx/condvar.rs
@@ -7,6 +7,8 @@
     inner: SpinMutex<WaitVariable<()>>,
 }
 
+pub type MovableCondvar = Box<Condvar>;
+
 impl Condvar {
     pub const fn new() -> Condvar {
         Condvar { inner: SpinMutex::new(WaitVariable::new(())) }
@@ -27,13 +29,13 @@
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
         let guard = self.inner.lock();
-        WaitQueue::wait(guard, || mutex.unlock());
-        mutex.lock()
+        WaitQueue::wait(guard, || unsafe { mutex.unlock() });
+        unsafe { mutex.lock() }
     }
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock());
-        mutex.lock();
+        let success = WaitQueue::wait_timeout(&self.inner, dur, || unsafe { mutex.unlock() });
+        unsafe { mutex.lock() };
         success
     }
 
diff --git a/library/std/src/sys/sgx/env.rs b/library/std/src/sys/sgx/env.rs
index 6fa0ed7..8043b7c 100644
--- a/library/std/src/sys/sgx/env.rs
+++ b/library/std/src/sys/sgx/env.rs
@@ -1,9 +1,9 @@
 pub mod os {
-    pub const FAMILY: &'static str = "";
-    pub const OS: &'static str = "";
-    pub const DLL_PREFIX: &'static str = "";
-    pub const DLL_SUFFIX: &'static str = ".sgxs";
-    pub const DLL_EXTENSION: &'static str = "sgxs";
-    pub const EXE_SUFFIX: &'static str = ".sgxs";
-    pub const EXE_EXTENSION: &'static str = "sgxs";
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = ".sgxs";
+    pub const DLL_EXTENSION: &str = "sgxs";
+    pub const EXE_SUFFIX: &str = ".sgxs";
+    pub const EXE_EXTENSION: &str = "sgxs";
 }
diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/sys/sgx/ext/arch.rs
index 0c97a87..7488e7e 100644
--- a/library/std/src/sys/sgx/ext/arch.rs
+++ b/library/std/src/sys/sgx/ext/arch.rs
@@ -31,13 +31,13 @@
         let mut out = MaybeUninit::uninit();
         let error;
 
-        llvm_asm!(
-            "enclu"
-            : "={eax}"(error)
-            : "{eax}"(ENCLU_EGETKEY),
-              "{rbx}"(request),
-              "{rcx}"(out.as_mut_ptr())
-            : "flags"
+        asm!(
+            "enclu",
+            inlateout("eax") ENCLU_EGETKEY => error,
+            in("rbx") request,
+            in("rcx") out.as_mut_ptr(),
+            // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9.
+            options(att_syntax, nostack),
         );
 
         match error {
@@ -60,13 +60,14 @@
     unsafe {
         let mut report = MaybeUninit::uninit();
 
-        llvm_asm!(
-            "enclu"
-            : /* no output registers */
-            : "{eax}"(ENCLU_EREPORT),
-              "{rbx}"(targetinfo),
-              "{rcx}"(reportdata),
-              "{rdx}"(report.as_mut_ptr())
+        asm!(
+            "enclu",
+            in("eax") ENCLU_EREPORT,
+            in("rbx") targetinfo,
+            in("rcx") reportdata,
+            in("rdx") report.as_mut_ptr(),
+            // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9.
+            options(att_syntax, preserves_flags, nostack),
         );
 
         report.assume_init()
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index 1abd91e..b10bed6 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -2,6 +2,7 @@
 //!
 //! This module contains the facade (aka platform-specific) implementations of
 //! OS level functionality for Fortanix SGX.
+#![deny(unsafe_op_in_unsafe_fn)]
 
 use crate::io::ErrorKind;
 use crate::os::raw::c_char;
@@ -121,9 +122,9 @@
 
 pub unsafe fn strlen(mut s: *const c_char) -> usize {
     let mut n = 0;
-    while *s != 0 {
+    while unsafe { *s } != 0 {
         n += 1;
-        s = s.offset(1);
+        s = unsafe { s.offset(1) };
     }
     return n;
 }
diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs
index 4911c2f..8874517 100644
--- a/library/std/src/sys/sgx/mutex.rs
+++ b/library/std/src/sys/sgx/mutex.rs
@@ -8,6 +8,8 @@
     inner: SpinMutex<WaitVariable<bool>>,
 }
 
+pub type MovableMutex = Box<Mutex>;
+
 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
 impl Mutex {
     pub const fn new() -> Mutex {
diff --git a/library/std/src/sys/sgx/path.rs b/library/std/src/sys/sgx/path.rs
index 06c9df3..840a7ae 100644
--- a/library/std/src/sys/sgx/path.rs
+++ b/library/std/src/sys/sgx/path.rs
@@ -15,5 +15,5 @@
     None
 }
 
-pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP_STR: &str = "/";
 pub const MAIN_SEP: char = '/';
diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs
index 3bf2a7d..0c96e3f 100644
--- a/library/std/src/sys/sgx/rwlock.rs
+++ b/library/std/src/sys/sgx/rwlock.rs
@@ -14,9 +14,12 @@
 }
 
 // Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below)
+//
+// # Safety
+// Never called, as it is a compile time check.
 #[allow(dead_code)]
 unsafe fn rw_lock_size_assert(r: RWLock) {
-    mem::transmute::<RWLock, [u8; 144]>(r);
+    unsafe { mem::transmute::<RWLock, [u8; 144]>(r) };
 }
 
 impl RWLock {
@@ -112,7 +115,7 @@
     pub unsafe fn read_unlock(&self) {
         let rguard = self.readers.lock();
         let wguard = self.writer.lock();
-        self.__read_unlock(rguard, wguard);
+        unsafe { self.__read_unlock(rguard, wguard) };
     }
 
     #[inline]
@@ -148,7 +151,7 @@
     pub unsafe fn write_unlock(&self) {
         let rguard = self.readers.lock();
         let wguard = self.writer.lock();
-        self.__write_unlock(rguard, wguard);
+        unsafe { self.__write_unlock(rguard, wguard) };
     }
 
     // only used by __rust_rwlock_unlock below
@@ -158,9 +161,9 @@
         let rguard = self.readers.lock();
         let wguard = self.writer.lock();
         if *wguard.lock_var() == true {
-            self.__write_unlock(rguard, wguard);
+            unsafe { self.__write_unlock(rguard, wguard) };
         } else {
-            self.__read_unlock(rguard, wguard);
+            unsafe { self.__read_unlock(rguard, wguard) };
         }
     }
 
@@ -179,7 +182,7 @@
     if p.is_null() {
         return EINVAL;
     }
-    (*p).read();
+    unsafe { (*p).read() };
     return 0;
 }
 
@@ -189,7 +192,7 @@
     if p.is_null() {
         return EINVAL;
     }
-    (*p).write();
+    unsafe { (*p).write() };
     return 0;
 }
 #[cfg(not(test))]
@@ -198,6 +201,6 @@
     if p.is_null() {
         return EINVAL;
     }
-    (*p).unlock();
+    unsafe { (*p).unlock() };
     return 0;
 }
diff --git a/library/std/src/sys/sgx/stdio.rs b/library/std/src/sys/sgx/stdio.rs
index 49f44f9..548e28a 100644
--- a/library/std/src/sys/sgx/stdio.rs
+++ b/library/std/src/sys/sgx/stdio.rs
@@ -81,7 +81,7 @@
     if s < 0 {
         return;
     }
-    let buf = slice::from_raw_parts(m as *const u8, s as _);
+    let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) };
     if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
         eprint!("{}", s);
     }
diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs
index 5895f70..55ef460c 100644
--- a/library/std/src/sys/sgx/thread.rs
+++ b/library/std/src/sys/sgx/thread.rs
@@ -51,7 +51,7 @@
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
         let mut queue_lock = task_queue::lock();
-        usercalls::launch_thread()?;
+        unsafe { usercalls::launch_thread()? };
         let (task, handle) = task_queue::Task::new(p);
         queue_lock.push(task);
         Ok(Thread(handle))
diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
index 7a24654..0834d25 100644
--- a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
+++ b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
@@ -30,31 +30,34 @@
         unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } }
     }
 
+    /// # Safety
     unsafe fn init(&mut self) {
         if self.head_tail_entry.is_none() {
             self.head_tail_entry = Some(UnsafeListEntry::dummy());
-            self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap());
-            self.head_tail.as_mut().next = self.head_tail;
-            self.head_tail.as_mut().prev = self.head_tail;
+            // SAFETY: `head_tail_entry` must be non-null, which it is because we assign it above.
+            self.head_tail =
+                unsafe { NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()) };
+            // SAFETY: `self.head_tail` must meet all requirements for a mutable reference.
+            unsafe { self.head_tail.as_mut() }.next = self.head_tail;
+            unsafe { self.head_tail.as_mut() }.prev = self.head_tail;
         }
     }
 
     pub fn is_empty(&self) -> bool {
-        unsafe {
-            if self.head_tail_entry.is_some() {
-                let first = self.head_tail.as_ref().next;
-                if first == self.head_tail {
-                    // ,-------> /---------\ next ---,
-                    // |         |head_tail|         |
-                    // `--- prev \---------/ <-------`
-                    rtassert!(self.head_tail.as_ref().prev == first);
-                    true
-                } else {
-                    false
-                }
-            } else {
+        if self.head_tail_entry.is_some() {
+            let first = unsafe { self.head_tail.as_ref() }.next;
+            if first == self.head_tail {
+                // ,-------> /---------\ next ---,
+                // |         |head_tail|         |
+                // `--- prev \---------/ <-------`
+                // SAFETY: `self.head_tail` must meet all requirements for a reference.
+                unsafe { rtassert!(self.head_tail.as_ref().prev == first) };
                 true
+            } else {
+                false
             }
+        } else {
+            true
         }
     }
 
@@ -67,7 +70,7 @@
     /// care must be taken in the caller of `push` to ensure unwinding does
     /// not destroy the stack frame containing the entry.
     pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
-        self.init();
+        unsafe { self.init() };
 
         // BEFORE:
         //     /---------\ next ---> /---------\
@@ -78,13 +81,15 @@
         //     /---------\ next ---> /-----\ next ---> /---------\
         // ... |prev_tail|           |entry|           |head_tail| ...
         //     \---------/ <--- prev \-----/ <--- prev \---------/
-        let mut entry = NonNull::new_unchecked(entry);
-        let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry);
-        entry.as_mut().prev = prev_tail;
-        entry.as_mut().next = self.head_tail;
-        prev_tail.as_mut().next = entry;
+        let mut entry = unsafe { NonNull::new_unchecked(entry) };
+        let mut prev_tail = mem::replace(&mut unsafe { self.head_tail.as_mut() }.prev, entry);
+        // SAFETY: `entry` must meet all requirements for a mutable reference.
+        unsafe { entry.as_mut() }.prev = prev_tail;
+        unsafe { entry.as_mut() }.next = self.head_tail;
+        // SAFETY: `prev_tail` must meet all requirements for a mutable reference.
+        unsafe { prev_tail.as_mut() }.next = entry;
         // unwrap ok: always `Some` on non-dummy entries
-        (*entry.as_ptr()).value.as_ref().unwrap()
+        unsafe { (*entry.as_ptr()).value.as_ref() }.unwrap()
     }
 
     /// Pops an entry from the front of the list.
@@ -94,7 +99,7 @@
     /// The caller must make sure to synchronize ending the borrow of the
     /// return value and deallocation of the containing entry.
     pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
-        self.init();
+        unsafe { self.init() };
 
         if self.is_empty() {
             None
@@ -108,14 +113,14 @@
             //     /---------\ next ---> /------\
             // ... |head_tail|           |second| ...
             //     \---------/ <--- prev \------/
-            let mut first = self.head_tail.as_mut().next;
-            let mut second = first.as_mut().next;
-            self.head_tail.as_mut().next = second;
-            second.as_mut().prev = self.head_tail;
-            first.as_mut().next = NonNull::dangling();
-            first.as_mut().prev = NonNull::dangling();
+            let mut first = unsafe { self.head_tail.as_mut() }.next;
+            let mut second = unsafe { first.as_mut() }.next;
+            unsafe { self.head_tail.as_mut() }.next = second;
+            unsafe { second.as_mut() }.prev = self.head_tail;
+            unsafe { first.as_mut() }.next = NonNull::dangling();
+            unsafe { first.as_mut() }.prev = NonNull::dangling();
             // unwrap ok: always `Some` on non-dummy entries
-            Some((*first.as_ptr()).value.as_ref().unwrap())
+            Some(unsafe { (*first.as_ptr()).value.as_ref() }.unwrap())
         }
     }
 
@@ -138,8 +143,9 @@
         //     \----/ <--- prev \----/
         let mut prev = entry.prev;
         let mut next = entry.next;
-        prev.as_mut().next = next;
-        next.as_mut().prev = prev;
+        // SAFETY: `prev` and `next` must meet all requirements for a mutable reference.entry
+        unsafe { prev.as_mut() }.next = next;
+        unsafe { next.as_mut() }.prev = prev;
         entry.next = NonNull::dangling();
         entry.prev = NonNull::dangling();
     }
diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs
index 1f031ed..c653dee 100644
--- a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs
+++ b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs
@@ -1,8 +1,10 @@
 use super::*;
 use crate::cell::Cell;
 
+/// # Safety
+/// List must be valid.
 unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) {
-    assert!(list.pop().is_none(), "assertion failed: list is not empty");
+    assert!(unsafe { list.pop() }.is_none(), "assertion failed: list is not empty");
 }
 
 #[test]
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index 9bc44a5..6967647 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -70,7 +70,8 @@
     target_os = "haiku",
     target_os = "l4re",
     target_os = "fuchsia",
-    target_os = "redox"
+    target_os = "redox",
+    target_os = "vxworks"
 ))]
 mod imp {
     use super::Args;
@@ -80,13 +81,13 @@
     use crate::ptr;
     use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
 
-    use crate::sys_common::mutex::Mutex;
+    use crate::sys_common::mutex::StaticMutex;
 
     static ARGC: AtomicIsize = AtomicIsize::new(0);
     static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
     // We never call `ENV_LOCK.init()`, so it is UB to attempt to
     // acquire this mutex reentrantly!
-    static LOCK: Mutex = Mutex::new();
+    static LOCK: StaticMutex = StaticMutex::new();
 
     unsafe fn really_init(argc: isize, argv: *const *const u8) {
         let _guard = LOCK.lock();
diff --git a/library/std/src/sys/unix/condvar.rs b/library/std/src/sys/unix/condvar.rs
index 9f18479..e38f91a 100644
--- a/library/std/src/sys/unix/condvar.rs
+++ b/library/std/src/sys/unix/condvar.rs
@@ -6,6 +6,8 @@
     inner: UnsafeCell<libc::pthread_cond_t>,
 }
 
+pub type MovableCondvar = Box<Condvar>;
+
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs
index 4b9f4ce..66bbc1c 100644
--- a/library/std/src/sys/unix/ext/fs.rs
+++ b/library/std/src/sys/unix/ext/fs.rs
@@ -650,6 +650,9 @@
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn blocks(&self) -> u64;
+    #[cfg(target_os = "vxworks")]
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn attrib(&self) -> u8;
 }
 
 #[stable(feature = "metadata_ext", since = "1.1.0")]
@@ -702,6 +705,10 @@
     fn blocks(&self) -> u64 {
         self.st_blocks()
     }
+    #[cfg(target_os = "vxworks")]
+    fn attrib(&self) -> u8 {
+        self.st_attrib()
+    }
 }
 
 /// Unix-specific extensions for [`fs::FileType`].
diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs
index ec7a32b..ef3c689 100644
--- a/library/std/src/sys/unix/ext/io.rs
+++ b/library/std/src/sys/unix/ext/io.rs
@@ -25,6 +25,19 @@
     /// This method does **not** pass ownership of the raw file descriptor
     /// to the caller. The descriptor is only guaranteed to be valid while
     /// the original object has not yet been destroyed.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{AsRawFd, RawFd};
+    ///
+    /// let mut f = File::open("foo.txt")?;
+    /// // Note that `raw_fd` is only valid as long as `f` exists.
+    /// let raw_fd: RawFd = f.as_raw_fd();
+    /// # Ok::<(), io::Error>(())
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_raw_fd(&self) -> RawFd;
 }
@@ -45,6 +58,21 @@
     /// descriptor they are wrapping. Usage of this function could
     /// accidentally allow violating this contract which can cause memory
     /// unsafety in code that relies on it being true.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
+    ///
+    /// let f = File::open("foo.txt")?;
+    /// let raw_fd: RawFd = f.into_raw_fd();
+    /// // SAFETY: no other functions should call `from_raw_fd`, so there
+    /// // is only one owner for the file descriptor.
+    /// let f = unsafe { File::from_raw_fd(raw_fd) };
+    /// # Ok::<(), io::Error>(())
+    /// ```
     #[stable(feature = "from_raw_os", since = "1.1.0")]
     unsafe fn from_raw_fd(fd: RawFd) -> Self;
 }
@@ -58,10 +86,41 @@
     /// This function **transfers ownership** of the underlying file descriptor
     /// to the caller. Callers are then the unique owners of the file descriptor
     /// and must close the descriptor once it's no longer needed.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{IntoRawFd, RawFd};
+    ///
+    /// let f = File::open("foo.txt")?;
+    /// let raw_fd: RawFd = f.into_raw_fd();
+    /// # Ok::<(), io::Error>(())
+    /// ```
     #[stable(feature = "into_raw_os", since = "1.4.0")]
     fn into_raw_fd(self) -> RawFd;
 }
 
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRawFd for fs::File {
     fn as_raw_fd(&self) -> RawFd {
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs
index 82527c4..3615a8a 100644
--- a/library/std/src/sys/unix/ext/process.rs
+++ b/library/std/src/sys/unix/ext/process.rs
@@ -16,12 +16,20 @@
     /// `setuid` call in the child process. Failure in the `setuid`
     /// call will cause the spawn to fail.
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn uid(&mut self, id: u32) -> &mut process::Command;
+    fn uid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command;
 
     /// Similar to `uid`, but sets the group ID of the child process. This has
     /// the same semantics as the `uid` field.
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn gid(&mut self, id: u32) -> &mut process::Command;
+    fn gid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command;
 
     /// Schedules a closure to be run just before the `exec` function is
     /// invoked.
@@ -115,12 +123,20 @@
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl CommandExt for process::Command {
-    fn uid(&mut self, id: u32) -> &mut process::Command {
+    fn uid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command {
         self.as_inner_mut().uid(id);
         self
     }
 
-    fn gid(&mut self, id: u32) -> &mut process::Command {
+    fn gid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command {
         self.as_inner_mut().gid(id);
         self
     }
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 2224a05..d3a279a 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -200,7 +200,8 @@
         target_os = "l4re",
         target_os = "linux",
         target_os = "haiku",
-        target_os = "redox"
+        target_os = "redox",
+        target_os = "vxworks"
     )))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
@@ -217,7 +218,8 @@
         target_os = "l4re",
         target_os = "linux",
         target_os = "haiku",
-        target_os = "redox"
+        target_os = "redox",
+        target_os = "vxworks"
     ))]
     pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 566ac09..d27d6e2 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -183,9 +183,14 @@
     root: PathBuf,
 }
 
-#[derive(Clone)]
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
+    #[cfg(not(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "fuchsia",
+        target_os = "redox",
+    )))]
     end_of_stream: bool,
 }
 
@@ -196,7 +201,7 @@
 
 pub struct DirEntry {
     entry: dirent64,
-    dir: ReadDir,
+    dir: Arc<InnerReadDir>,
     // We need to store an owned copy of the entry name
     // on Solaris and Fuchsia because a) it uses a zero-length
     // array to store the name, b) its lifetime between readdir
@@ -292,6 +297,7 @@
 
 #[cfg(not(target_os = "netbsd"))]
 impl FileAttr {
+    #[cfg(not(target_os = "vxworks"))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(libc::timespec {
             tv_sec: self.stat.st_mtime as libc::time_t,
@@ -299,6 +305,15 @@
         }))
     }
 
+    #[cfg(target_os = "vxworks")]
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from(libc::timespec {
+            tv_sec: self.stat.st_mtime as libc::time_t,
+            tv_nsec: 0,
+        }))
+    }
+
+    #[cfg(not(target_os = "vxworks"))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(libc::timespec {
             tv_sec: self.stat.st_atime as libc::time_t,
@@ -306,6 +321,14 @@
         }))
     }
 
+    #[cfg(target_os = "vxworks")]
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from(libc::timespec {
+            tv_sec: self.stat.st_atime as libc::time_t,
+            tv_nsec: 0,
+        }))
+    }
+
     #[cfg(any(
         target_os = "freebsd",
         target_os = "openbsd",
@@ -443,7 +466,7 @@
                     name: slice::from_raw_parts(name as *const u8, namelen as usize)
                         .to_owned()
                         .into_boxed_slice(),
-                    dir: self.clone(),
+                    dir: Arc::clone(&self.inner),
                 };
                 if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
                     return Some(Ok(ret));
@@ -464,7 +487,7 @@
         }
 
         unsafe {
-            let mut ret = DirEntry { entry: mem::zeroed(), dir: self.clone() };
+            let mut ret = DirEntry { entry: mem::zeroed(), dir: Arc::clone(&self.inner) };
             let mut entry_ptr = ptr::null_mut();
             loop {
                 if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
@@ -497,7 +520,7 @@
 
 impl DirEntry {
     pub fn path(&self) -> PathBuf {
-        self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
+        self.dir.root.join(OsStr::from_bytes(self.name_bytes()))
     }
 
     pub fn file_name(&self) -> OsString {
@@ -506,7 +529,7 @@
 
     #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
-        let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?;
+        let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?;
         let name = self.entry.d_name.as_ptr();
 
         cfg_has_statx! {
@@ -530,12 +553,22 @@
         lstat(&self.path())
     }
 
-    #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "haiku"))]
+    #[cfg(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "haiku",
+        target_os = "vxworks"
+    ))]
     pub fn file_type(&self) -> io::Result<FileType> {
         lstat(&self.path()).map(|m| m.file_type())
     }
 
-    #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "haiku")))]
+    #[cfg(not(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "haiku",
+        target_os = "vxworks"
+    )))]
     pub fn file_type(&self) -> io::Result<FileType> {
         match self.entry.d_type {
             libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@@ -560,7 +593,8 @@
         target_os = "haiku",
         target_os = "l4re",
         target_os = "fuchsia",
-        target_os = "redox"
+        target_os = "redox",
+        target_os = "vxworks"
     ))]
     pub fn ino(&self) -> u64 {
         self.entry.d_ino as u64
@@ -598,7 +632,8 @@
         target_os = "linux",
         target_os = "emscripten",
         target_os = "l4re",
-        target_os = "haiku"
+        target_os = "haiku",
+        target_os = "vxworks"
     ))]
     fn name_bytes(&self) -> &[u8] {
         unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() }
@@ -752,11 +787,25 @@
         unsafe fn os_datasync(fd: c_int) -> c_int {
             libc::fcntl(fd, libc::F_FULLFSYNC)
         }
-        #[cfg(target_os = "linux")]
+        #[cfg(any(
+            target_os = "freebsd",
+            target_os = "linux",
+            target_os = "android",
+            target_os = "netbsd",
+            target_os = "openbsd"
+        ))]
         unsafe fn os_datasync(fd: c_int) -> c_int {
             libc::fdatasync(fd)
         }
-        #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))]
+        #[cfg(not(any(
+            target_os = "android",
+            target_os = "freebsd",
+            target_os = "ios",
+            target_os = "linux",
+            target_os = "macos",
+            target_os = "netbsd",
+            target_os = "openbsd"
+        )))]
         unsafe fn os_datasync(fd: c_int) -> c_int {
             libc::fsync(fd)
         }
@@ -896,13 +945,25 @@
             Some(PathBuf::from(OsString::from_vec(buf)))
         }
 
-        #[cfg(not(any(target_os = "linux", target_os = "macos")))]
+        #[cfg(target_os = "vxworks")]
+        fn get_path(fd: c_int) -> Option<PathBuf> {
+            let mut buf = vec![0; libc::PATH_MAX as usize];
+            let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) };
+            if n == -1 {
+                return None;
+            }
+            let l = buf.iter().position(|&c| c == 0).unwrap();
+            buf.truncate(l as usize);
+            Some(PathBuf::from(OsString::from_vec(buf)))
+        }
+
+        #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))]
         fn get_path(_fd: c_int) -> Option<PathBuf> {
             // FIXME(#24570): implement this for other Unix platforms
             None
         }
 
-        #[cfg(any(target_os = "linux", target_os = "macos"))]
+        #[cfg(any(target_os = "linux", target_os = "macos", target_os = "vxworks"))]
         fn get_mode(fd: c_int) -> Option<(bool, bool)> {
             let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
             if mode == -1 {
@@ -916,7 +977,7 @@
             }
         }
 
-        #[cfg(not(any(target_os = "linux", target_os = "macos")))]
+        #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))]
         fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
             // FIXME(#24570): implement this for other Unix platforms
             None
@@ -944,7 +1005,16 @@
             Err(Error::last_os_error())
         } else {
             let inner = InnerReadDir { dirp: Dir(ptr), root };
-            Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false })
+            Ok(ReadDir {
+                inner: Arc::new(inner),
+                #[cfg(not(any(
+                    target_os = "solaris",
+                    target_os = "illumos",
+                    target_os = "fuchsia",
+                    target_os = "redox",
+                )))]
+                end_of_stream: false,
+            })
         }
     }
 }
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
new file mode 100644
index 0000000..e6f0c48
--- /dev/null
+++ b/library/std/src/sys/unix/futex.rs
@@ -0,0 +1,37 @@
+#![cfg(any(target_os = "linux", target_os = "android"))]
+
+use crate::convert::TryInto;
+use crate::ptr::null;
+use crate::sync::atomic::AtomicI32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
+    let timespec = timeout.and_then(|d| {
+        Some(libc::timespec {
+            // Sleep forever if the timeout is longer than fits in a timespec.
+            tv_sec: d.as_secs().try_into().ok()?,
+            // This conversion never truncates, as subsec_nanos is always <1e9.
+            tv_nsec: d.subsec_nanos() as _,
+        })
+    });
+    unsafe {
+        libc::syscall(
+            libc::SYS_futex,
+            futex as *const AtomicI32,
+            libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
+            expected,
+            timespec.as_ref().map_or(null(), |d| d as *const libc::timespec),
+        );
+    }
+}
+
+pub fn futex_wake(futex: &AtomicI32) {
+    unsafe {
+        libc::syscall(
+            libc::SYS_futex,
+            futex as *const AtomicI32,
+            libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
+            1,
+        );
+    }
+}
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index b48d216..b28c6d8 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -49,6 +49,7 @@
 pub mod ext;
 pub mod fd;
 pub mod fs;
+pub mod futex;
 pub mod io;
 #[cfg(target_os = "l4re")]
 mod l4re;
@@ -93,60 +94,61 @@
         reset_sigpipe();
     }
 
-    // In the case when all file descriptors are open, the poll has been
-    // observed to perform better than fcntl (on GNU/Linux).
-    #[cfg(not(any(
-        miri,
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        // The poll on Darwin doesn't set POLLNVAL for closed fds.
-        target_os = "macos",
-        target_os = "ios",
-        target_os = "redox",
-    )))]
-    unsafe fn sanitize_standard_fds() {
-        use crate::sys::os::errno;
-        let pfds: &mut [_] = &mut [
-            libc::pollfd { fd: 0, events: 0, revents: 0 },
-            libc::pollfd { fd: 1, events: 0, revents: 0 },
-            libc::pollfd { fd: 2, events: 0, revents: 0 },
-        ];
-        while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 {
-            if errno() == libc::EINTR {
-                continue;
-            }
-            libc::abort();
-        }
-        for pfd in pfds {
-            if pfd.revents & libc::POLLNVAL == 0 {
-                continue;
-            }
-            if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
-                // If the stream is closed but we failed to reopen it, abort the
-                // process. Otherwise we wouldn't preserve the safety of
-                // operations on the corresponding Rust object Stdin, Stdout, or
-                // Stderr.
-                libc::abort();
-            }
-        }
-    }
-    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))]
-    unsafe fn sanitize_standard_fds() {
-        use crate::sys::os::errno;
-        for fd in 0..3 {
-            if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
-                if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+    cfg_if::cfg_if! {
+        if #[cfg(miri)] {
+            // The standard fds are always available in Miri.
+            unsafe fn sanitize_standard_fds() {}
+        } else if #[cfg(not(any(
+            target_os = "emscripten",
+            target_os = "fuchsia",
+            // The poll on Darwin doesn't set POLLNVAL for closed fds.
+            target_os = "macos",
+            target_os = "ios",
+            target_os = "redox",
+        )))] {
+            // In the case when all file descriptors are open, the poll has been
+            // observed to perform better than fcntl (on GNU/Linux).
+            unsafe fn sanitize_standard_fds() {
+                use crate::sys::os::errno;
+                let pfds: &mut [_] = &mut [
+                    libc::pollfd { fd: 0, events: 0, revents: 0 },
+                    libc::pollfd { fd: 1, events: 0, revents: 0 },
+                    libc::pollfd { fd: 2, events: 0, revents: 0 },
+                ];
+                while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 {
+                    if errno() == libc::EINTR {
+                        continue;
+                    }
                     libc::abort();
                 }
+                for pfd in pfds {
+                    if pfd.revents & libc::POLLNVAL == 0 {
+                        continue;
+                    }
+                    if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                        // If the stream is closed but we failed to reopen it, abort the
+                        // process. Otherwise we wouldn't preserve the safety of
+                        // operations on the corresponding Rust object Stdin, Stdout, or
+                        // Stderr.
+                        libc::abort();
+                    }
+                }
             }
+        } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] {
+            unsafe fn sanitize_standard_fds() {
+                use crate::sys::os::errno;
+                for fd in 0..3 {
+                    if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
+                        if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+                            libc::abort();
+                        }
+                    }
+                }
+            }
+        } else {
+            unsafe fn sanitize_standard_fds() {}
         }
     }
-    #[cfg(any(
-        // The standard fds are always available in Miri.
-        miri,
-        target_os = "emscripten",
-        target_os = "fuchsia"))]
-    unsafe fn sanitize_standard_fds() {}
 
     #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
     unsafe fn reset_sigpipe() {
@@ -218,6 +220,10 @@
     }
 }
 
+pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
+    if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
+}
+
 // On Unix-like platforms, libc::abort will unregister signal handlers
 // including the SIGABRT handler, preventing the abort from being blocked, and
 // fclose streams, with the side effect of flushing them so libc buffered
diff --git a/library/std/src/sys/unix/mutex.rs b/library/std/src/sys/unix/mutex.rs
index 45c600f..89c55eb 100644
--- a/library/std/src/sys/unix/mutex.rs
+++ b/library/std/src/sys/unix/mutex.rs
@@ -1,10 +1,13 @@
 use crate::cell::UnsafeCell;
 use crate::mem::MaybeUninit;
+use crate::sys::cvt_nz;
 
 pub struct Mutex {
     inner: UnsafeCell<libc::pthread_mutex_t>,
 }
 
+pub type MovableMutex = Box<Mutex>;
+
 #[inline]
 pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
     m.inner.get()
@@ -49,14 +52,11 @@
         // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
         // re-lock it from the same thread, thus avoiding undefined behavior.
         let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
-        let r = libc::pthread_mutexattr_init(attr.as_mut_ptr());
-        debug_assert_eq!(r, 0);
-        let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL);
-        debug_assert_eq!(r, 0);
-        let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr());
-        debug_assert_eq!(r, 0);
-        let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
-        debug_assert_eq!(r, 0);
+        cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
+        let attr = PthreadMutexAttr(&mut attr);
+        cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL))
+            .unwrap();
+        cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
     }
     #[inline]
     pub unsafe fn lock(&self) {
@@ -104,15 +104,11 @@
 
     pub unsafe fn init(&self) {
         let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
-        let result = libc::pthread_mutexattr_init(attr.as_mut_ptr());
-        debug_assert_eq!(result, 0);
-        let result =
-            libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE);
-        debug_assert_eq!(result, 0);
-        let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr());
-        debug_assert_eq!(result, 0);
-        let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
-        debug_assert_eq!(result, 0);
+        cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
+        let attr = PthreadMutexAttr(&mut attr);
+        cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE))
+            .unwrap();
+        cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
     }
 
     pub unsafe fn lock(&self) {
@@ -135,3 +131,14 @@
         debug_assert_eq!(result, 0);
     }
 }
+
+struct PthreadMutexAttr<'a>(&'a mut MaybeUninit<libc::pthread_mutexattr_t>);
+
+impl Drop for PthreadMutexAttr<'_> {
+    fn drop(&mut self) {
+        unsafe {
+            let result = libc::pthread_mutexattr_destroy(self.0.as_mut_ptr());
+            debug_assert_eq!(result, 0);
+        }
+    }
+}
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 011325f..74c7db2 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -77,6 +77,7 @@
         }
     }
 
+    #[cfg(not(target_os = "vxworks"))]
     pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
         unsafe {
             let mut fds = [0, 0];
@@ -98,6 +99,11 @@
         }
     }
 
+    #[cfg(target_os = "vxworks")]
+    pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> {
+        unimplemented!()
+    }
+
     pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
         self.set_nonblocking(true)?;
         let r = unsafe {
@@ -366,7 +372,7 @@
 // res_init unconditionally, we call it only when we detect we're linking
 // against glibc version < 2.26. (That is, when we both know its needed and
 // believe it's thread-safe).
-#[cfg(target_env = "gnu")]
+#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
 fn on_resolver_failure() {
     use crate::sys;
 
@@ -378,5 +384,5 @@
     }
 }
 
-#[cfg(not(target_env = "gnu"))]
+#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))]
 fn on_resolver_failure() {}
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 4aa61fc..d5e14be 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -21,7 +21,7 @@
 use crate::str;
 use crate::sys::cvt;
 use crate::sys::fd;
-use crate::sys_common::mutex::{Mutex, MutexGuard};
+use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
 use crate::vec;
 
 use libc::{c_char, c_int, c_void};
@@ -37,7 +37,7 @@
 }
 
 extern "C" {
-    #[cfg(not(target_os = "dragonfly"))]
+    #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
     #[cfg_attr(
         any(
             target_os = "linux",
@@ -67,18 +67,28 @@
 }
 
 /// Returns the platform-specific value of errno
-#[cfg(not(target_os = "dragonfly"))]
+#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
 pub fn errno() -> i32 {
     unsafe { (*errno_location()) as i32 }
 }
 
 /// Sets the platform-specific value of errno
-#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall!
+#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
 #[allow(dead_code)] // but not all target cfgs actually end up using it
 pub fn set_errno(e: i32) {
     unsafe { *errno_location() = e as c_int }
 }
 
+#[cfg(target_os = "vxworks")]
+pub fn errno() -> i32 {
+    unsafe { libc::errnoGet() }
+}
+
+#[cfg(target_os = "vxworks")]
+pub fn set_errno(e: i32) {
+    unsafe { libc::errnoSet(e as c_int) };
+}
+
 #[cfg(target_os = "dragonfly")]
 pub fn errno() -> i32 {
     extern "C" {
@@ -439,6 +449,19 @@
     Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
 }
 
+#[cfg(target_os = "vxworks")]
+pub fn current_exe() -> io::Result<PathBuf> {
+    #[cfg(test)]
+    use realstd::env;
+
+    #[cfg(not(test))]
+    use crate::env;
+
+    let exe_path = env::args().next().unwrap();
+    let path = path::Path::new(&exe_path);
+    path.canonicalize()
+}
+
 pub struct Env {
     iter: vec::IntoIter<(OsString, OsString)>,
     _dont_send_or_sync_me: PhantomData<*mut ()>,
@@ -470,10 +493,9 @@
     &mut environ
 }
 
-pub unsafe fn env_lock() -> MutexGuard<'static> {
-    // We never call `ENV_LOCK.init()`, so it is UB to attempt to
-    // acquire this mutex reentrantly!
-    static ENV_LOCK: Mutex = Mutex::new();
+pub unsafe fn env_lock() -> StaticMutexGuard {
+    // It is UB to attempt to acquire this mutex reentrantly!
+    static ENV_LOCK: StaticMutex = StaticMutex::new();
     ENV_LOCK.lock()
 }
 
@@ -569,7 +591,8 @@
         target_os = "android",
         target_os = "ios",
         target_os = "emscripten",
-        target_os = "redox"
+        target_os = "redox",
+        target_os = "vxworks"
     ))]
     unsafe fn fallback() -> Option<OsString> {
         None
@@ -578,7 +601,8 @@
         target_os = "android",
         target_os = "ios",
         target_os = "emscripten",
-        target_os = "redox"
+        target_os = "redox",
+        target_os = "vxworks"
     )))]
     unsafe fn fallback() -> Option<OsString> {
         let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs
index 553e980..1b7b93f 100644
--- a/library/std/src/sys/unix/process/mod.rs
+++ b/library/std/src/sys/unix/process/mod.rs
@@ -1,6 +1,7 @@
-pub use self::process_common::{Command, ExitCode, Stdio, StdioPipes};
+pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
 pub use self::process_inner::{ExitStatus, Process};
 pub use crate::ffi::OsString as EnvKey;
+pub use crate::sys_common::process::CommandEnvs;
 
 mod process_common;
 #[cfg(not(target_os = "fuchsia"))]
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index f866648..372e5e6 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -7,11 +7,12 @@
 use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
 use crate::io;
+use crate::path::Path;
 use crate::ptr;
 use crate::sys::fd::FileDesc;
 use crate::sys::fs::File;
 use crate::sys::pipe::{self, AnonPipe};
-use crate::sys_common::process::CommandEnv;
+use crate::sys_common::process::{CommandEnv, CommandEnvs};
 
 #[cfg(not(target_os = "fuchsia"))]
 use crate::sys::fs::OpenOptions;
@@ -23,6 +24,8 @@
         // fuchsia doesn't have /dev/null
     } else if #[cfg(target_os = "redox")] {
         const DEV_NULL: &str = "null:\0";
+    } else if #[cfg(target_os = "vxworks")] {
+        const DEV_NULL: &str = "/null\0";
     } else {
         const DEV_NULL: &str = "/dev/null\0";
     }
@@ -47,7 +50,7 @@
             raw[bit / 8] |= 1 << (bit % 8);
             return 0;
         }
-    } else {
+    } else if #[cfg(not(target_os = "vxworks"))] {
         pub use libc::{sigemptyset, sigaddset};
     }
 }
@@ -184,11 +187,30 @@
     pub fn saw_nul(&self) -> bool {
         self.saw_nul
     }
+
+    pub fn get_program(&self) -> &OsStr {
+        OsStr::from_bytes(self.program.as_bytes())
+    }
+
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        let mut iter = self.args.iter();
+        iter.next();
+        CommandArgs { iter }
+    }
+
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        self.env.iter()
+    }
+
+    pub fn get_current_dir(&self) -> Option<&Path> {
+        self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes())))
+    }
+
     pub fn get_argv(&self) -> &Vec<*const c_char> {
         &self.argv.0
     }
 
-    pub fn get_program(&self) -> &CStr {
+    pub fn get_program_cstr(&self) -> &CStr {
         &*self.program
     }
 
@@ -233,11 +255,17 @@
         let maybe_env = self.env.capture_if_changed();
         maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
     }
+
     #[allow(dead_code)]
     pub fn env_saw_path(&self) -> bool {
         self.env.have_changed_path()
     }
 
+    #[allow(dead_code)]
+    pub fn program_is_path(&self) -> bool {
+        self.program.to_bytes().contains(&b'/')
+    }
+
     pub fn setup_io(
         &self,
         default: Stdio,
@@ -402,3 +430,32 @@
         self.0 as i32
     }
 }
+
+pub struct CommandArgs<'a> {
+    iter: crate::slice::Iter<'a, CString>,
+}
+
+impl<'a> Iterator for CommandArgs<'a> {
+    type Item = &'a OsStr;
+    fn next(&mut self) -> Option<&'a OsStr> {
+        self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes()))
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+impl<'a> ExactSizeIterator for CommandArgs<'a> {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+impl<'a> fmt::Debug for CommandArgs<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.iter.clone()).finish()
+    }
+}
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index fab27cd..b64636c 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -120,7 +120,7 @@
                 | FDIO_SPAWN_CLONE_NAMESPACE
                 | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
                 | FDIO_SPAWN_CLONE_UTC_CLOCK,
-            self.get_program().as_ptr(),
+            self.get_program_cstr().as_ptr(),
             self.get_argv().as_ptr(),
             envp,
             actions.len() as size_t,
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 08efe15..a590c74 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -6,6 +6,10 @@
 use crate::sys::cvt;
 use crate::sys::process::process_common::*;
 
+#[cfg(target_os = "vxworks")]
+use libc::RTP_ID as pid_t;
+
+#[cfg(not(target_os = "vxworks"))]
 use libc::{c_int, gid_t, pid_t, uid_t};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -67,7 +71,7 @@
                     // pipe I/O up to PIPE_BUF bytes should be atomic, and then
                     // we want to be sure we *don't* run at_exit destructors as
                     // we're being torn down regardless
-                    assert!(output.write(&bytes).is_ok());
+                    rtassert!(output.write(&bytes).is_ok());
                     libc::_exit(1)
                 }
                 n => n,
@@ -245,14 +249,15 @@
             *sys::os::environ() = envp.as_ptr();
         }
 
-        libc::execvp(self.get_program().as_ptr(), self.get_argv().as_ptr());
+        libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr());
         Err(io::Error::last_os_error())
     }
 
     #[cfg(not(any(
         target_os = "macos",
         target_os = "freebsd",
-        all(target_os = "linux", target_env = "gnu")
+        all(target_os = "linux", target_env = "gnu"),
+        all(target_os = "linux", target_env = "musl"),
     )))]
     fn posix_spawn(
         &mut self,
@@ -267,7 +272,8 @@
     #[cfg(any(
         target_os = "macos",
         target_os = "freebsd",
-        all(target_os = "linux", target_env = "gnu")
+        all(target_os = "linux", target_env = "gnu"),
+        all(target_os = "linux", target_env = "musl"),
     ))]
     fn posix_spawn(
         &mut self,
@@ -275,11 +281,11 @@
         envp: Option<&CStringArray>,
     ) -> io::Result<Option<Process>> {
         use crate::mem::MaybeUninit;
-        use crate::sys;
+        use crate::sys::{self, cvt_nz};
 
         if self.get_gid().is_some()
             || self.get_uid().is_some()
-            || self.env_saw_path()
+            || (self.env_saw_path() && !self.program_is_path())
             || !self.get_closures().is_empty()
         {
             return Ok(None);
@@ -297,10 +303,10 @@
             }
         }
 
-        // Solaris and glibc 2.29+ can set a new working directory, and maybe
-        // others will gain this non-POSIX function too. We'll check for this
-        // weak symbol as soon as it's needed, so we can return early otherwise
-        // to do a manual chdir before exec.
+        // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
+        // and maybe others will gain this non-POSIX function too. We'll check
+        // for this weak symbol as soon as it's needed, so we can return early
+        // otherwise to do a manual chdir before exec.
         weak! {
             fn posix_spawn_file_actions_addchdir_np(
                 *mut libc::posix_spawn_file_actions_t,
@@ -317,9 +323,9 @@
 
         let mut p = Process { pid: 0, status: None };
 
-        struct PosixSpawnFileActions(MaybeUninit<libc::posix_spawn_file_actions_t>);
+        struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
 
-        impl Drop for PosixSpawnFileActions {
+        impl Drop for PosixSpawnFileActions<'_> {
             fn drop(&mut self) {
                 unsafe {
                     libc::posix_spawn_file_actions_destroy(self.0.as_mut_ptr());
@@ -327,9 +333,9 @@
             }
         }
 
-        struct PosixSpawnattr(MaybeUninit<libc::posix_spawnattr_t>);
+        struct PosixSpawnattr<'a>(&'a mut MaybeUninit<libc::posix_spawnattr_t>);
 
-        impl Drop for PosixSpawnattr {
+        impl Drop for PosixSpawnattr<'_> {
             fn drop(&mut self) {
                 unsafe {
                     libc::posix_spawnattr_destroy(self.0.as_mut_ptr());
@@ -338,58 +344,60 @@
         }
 
         unsafe {
-            let mut file_actions = PosixSpawnFileActions(MaybeUninit::uninit());
-            let mut attrs = PosixSpawnattr(MaybeUninit::uninit());
+            let mut attrs = MaybeUninit::uninit();
+            cvt_nz(libc::posix_spawnattr_init(attrs.as_mut_ptr()))?;
+            let attrs = PosixSpawnattr(&mut attrs);
 
-            libc::posix_spawnattr_init(attrs.0.as_mut_ptr());
-            libc::posix_spawn_file_actions_init(file_actions.0.as_mut_ptr());
+            let mut file_actions = MaybeUninit::uninit();
+            cvt_nz(libc::posix_spawn_file_actions_init(file_actions.as_mut_ptr()))?;
+            let file_actions = PosixSpawnFileActions(&mut file_actions);
 
             if let Some(fd) = stdio.stdin.fd() {
-                cvt(libc::posix_spawn_file_actions_adddup2(
+                cvt_nz(libc::posix_spawn_file_actions_adddup2(
                     file_actions.0.as_mut_ptr(),
                     fd,
                     libc::STDIN_FILENO,
                 ))?;
             }
             if let Some(fd) = stdio.stdout.fd() {
-                cvt(libc::posix_spawn_file_actions_adddup2(
+                cvt_nz(libc::posix_spawn_file_actions_adddup2(
                     file_actions.0.as_mut_ptr(),
                     fd,
                     libc::STDOUT_FILENO,
                 ))?;
             }
             if let Some(fd) = stdio.stderr.fd() {
-                cvt(libc::posix_spawn_file_actions_adddup2(
+                cvt_nz(libc::posix_spawn_file_actions_adddup2(
                     file_actions.0.as_mut_ptr(),
                     fd,
                     libc::STDERR_FILENO,
                 ))?;
             }
             if let Some((f, cwd)) = addchdir {
-                cvt(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?;
+                cvt_nz(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?;
             }
 
             let mut set = MaybeUninit::<libc::sigset_t>::uninit();
             cvt(sigemptyset(set.as_mut_ptr()))?;
-            cvt(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?;
+            cvt_nz(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?;
             cvt(sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?;
-            cvt(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?;
+            cvt_nz(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?;
 
             let flags = libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK;
-            cvt(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
+            cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
 
             // Make sure we synchronize access to the global `environ` resource
             let _env_lock = sys::os::env_lock();
             let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
-            let ret = libc::posix_spawnp(
+            cvt_nz(libc::posix_spawnp(
                 &mut p.pid,
-                self.get_program().as_ptr(),
+                self.get_program_cstr().as_ptr(),
                 file_actions.0.as_ptr(),
                 attrs.0.as_ptr(),
                 self.get_argv().as_ptr() as *const _,
                 envp as *const _,
-            );
-            if ret == 0 { Ok(Some(p)) } else { Err(io::Error::from_raw_os_error(ret)) }
+            ))?;
+            Ok(Some(p))
         }
     }
 }
@@ -459,15 +467,7 @@
     }
 
     fn exited(&self) -> bool {
-        // On Linux-like OSes this function is safe, on others it is not. See
-        // libc issue: https://github.com/rust-lang/libc/issues/1888.
-        #[cfg_attr(
-            any(target_os = "linux", target_os = "android", target_os = "emscripten"),
-            allow(unused_unsafe)
-        )]
-        unsafe {
-            libc::WIFEXITED(self.0)
-        }
+        libc::WIFEXITED(self.0)
     }
 
     pub fn success(&self) -> bool {
@@ -475,23 +475,11 @@
     }
 
     pub fn code(&self) -> Option<i32> {
-        // On Linux-like OSes this function is safe, on others it is not. See
-        // libc issue: https://github.com/rust-lang/libc/issues/1888.
-        #[cfg_attr(
-            any(target_os = "linux", target_os = "android", target_os = "emscripten"),
-            allow(unused_unsafe)
-        )]
-        if self.exited() { Some(unsafe { libc::WEXITSTATUS(self.0) }) } else { None }
+        if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None }
     }
 
     pub fn signal(&self) -> Option<i32> {
-        // On Linux-like OSes this function is safe, on others it is not. See
-        // libc issue: https://github.com/rust-lang/libc/issues/1888.
-        #[cfg_attr(
-            any(target_os = "linux", target_os = "android", target_os = "emscripten"),
-            allow(unused_unsafe)
-        )]
-        if !self.exited() { Some(unsafe { libc::WTERMSIG(self.0) }) } else { None }
+        if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None }
     }
 }
 
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs
index c74fc2b..d847420 100644
--- a/library/std/src/sys/unix/stack_overflow.rs
+++ b/library/std/src/sys/unix/stack_overflow.rs
@@ -219,7 +219,7 @@
     target_os = "solaris",
     target_os = "illumos",
     all(target_os = "netbsd", not(target_vendor = "rumprun")),
-    target_os = "openbsd"
+    target_os = "openbsd",
 )))]
 mod imp {
     pub unsafe fn init() {}
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 652219e..fdf114d 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -6,10 +6,12 @@
 use crate::sys::{os, stack_overflow};
 use crate::time::Duration;
 
-#[cfg(not(target_os = "l4re"))]
+#[cfg(not(any(target_os = "l4re", target_os = "vxworks")))]
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
 #[cfg(target_os = "l4re")]
 pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
+#[cfg(target_os = "vxworks")]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
 
 pub struct Thread {
     id: libc::pthread_t,
@@ -152,10 +154,11 @@
         target_os = "haiku",
         target_os = "l4re",
         target_os = "emscripten",
-        target_os = "redox"
+        target_os = "redox",
+        target_os = "vxworks"
     ))]
     pub fn set_name(_name: &CStr) {
-        // Newlib, Haiku, and Emscripten have no way to set a thread name.
+        // Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name.
     }
     #[cfg(target_os = "fuchsia")]
     pub fn set_name(_name: &CStr) {
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index f2a9cb5..fac4b05 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -117,8 +117,7 @@
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 mod inner {
     use crate::fmt;
-    use crate::mem;
-    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+    use crate::sync::atomic::{AtomicU64, Ordering};
     use crate::sys::cvt;
     use crate::sys_common::mul_div_u64;
     use crate::time::Duration;
@@ -233,31 +232,42 @@
     }
 
     fn info() -> mach_timebase_info {
-        static mut INFO: mach_timebase_info = mach_timebase_info { numer: 0, denom: 0 };
-        static STATE: AtomicUsize = AtomicUsize::new(0);
+        // INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
+        // this in 64 bits because we know 0 is never a valid value for the
+        // `denom` field.
+        //
+        // Encoding this as a single `AtomicU64` allows us to use `Relaxed`
+        // operations, as we are only interested in in the effects on a single
+        // memory location.
+        static INFO_BITS: AtomicU64 = AtomicU64::new(0);
 
-        unsafe {
-            // If a previous thread has filled in this global state, use that.
-            if STATE.load(SeqCst) == 2 {
-                return INFO;
-            }
-
-            // ... otherwise learn for ourselves ...
-            let mut info = mem::zeroed();
-            extern "C" {
-                fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
-            }
-
-            mach_timebase_info(&mut info);
-
-            // ... and attempt to be the one thread that stores it globally for
-            // all other threads
-            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
-                INFO = info;
-                STATE.store(2, SeqCst);
-            }
-            return info;
+        // If a previous thread has initialized `INFO_BITS`, use it.
+        let info_bits = INFO_BITS.load(Ordering::Relaxed);
+        if info_bits != 0 {
+            return info_from_bits(info_bits);
         }
+
+        // ... otherwise learn for ourselves ...
+        extern "C" {
+            fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
+        }
+
+        let mut info = info_from_bits(0);
+        unsafe {
+            mach_timebase_info(&mut info);
+        }
+        INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);
+        info
+    }
+
+    #[inline]
+    fn info_to_bits(info: mach_timebase_info) -> u64 {
+        ((info.denom as u64) << 32) | (info.numer as u64)
+    }
+
+    #[inline]
+    fn info_from_bits(bits: u64) -> mach_timebase_info {
+        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
     }
 }
 
diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs
index 80311d2..2cdd9c4 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -39,10 +39,13 @@
 pub enum Void {}
 
 pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
+    // SAFETY: The caller must guarantee `s` points to a valid 0-terminated string.
+    unsafe {
+        let mut n = 0;
+        while *s != 0 {
+            n += 1;
+            s = s.offset(1);
+        }
+        n
     }
-    return n;
 }
diff --git a/library/std/src/sys/unsupported/condvar.rs b/library/std/src/sys/unsupported/condvar.rs
index a578eee..35d12a6 100644
--- a/library/std/src/sys/unsupported/condvar.rs
+++ b/library/std/src/sys/unsupported/condvar.rs
@@ -3,6 +3,8 @@
 
 pub struct Condvar {}
 
+pub type MovableCondvar = Condvar;
+
 impl Condvar {
     pub const fn new() -> Condvar {
         Condvar {}
diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs
index 8ba870c..d9efdec 100644
--- a/library/std/src/sys/unsupported/mod.rs
+++ b/library/std/src/sys/unsupported/mod.rs
@@ -1,3 +1,5 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
 pub mod alloc;
 pub mod args;
 pub mod cmath;
diff --git a/library/std/src/sys/unsupported/mutex.rs b/library/std/src/sys/unsupported/mutex.rs
index 9ef8af5..b3203c1 100644
--- a/library/std/src/sys/unsupported/mutex.rs
+++ b/library/std/src/sys/unsupported/mutex.rs
@@ -1,16 +1,18 @@
-use crate::cell::UnsafeCell;
+use crate::cell::Cell;
 
 pub struct Mutex {
-    locked: UnsafeCell<bool>,
+    // This platform has no threads, so we can use a Cell here.
+    locked: Cell<bool>,
 }
 
+pub type MovableMutex = Mutex;
+
 unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {} // no threads on this platform
 
 impl Mutex {
-    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Mutex {
-        Mutex { locked: UnsafeCell::new(false) }
+        Mutex { locked: Cell::new(false) }
     }
 
     #[inline]
@@ -18,25 +20,17 @@
 
     #[inline]
     pub unsafe fn lock(&self) {
-        let locked = self.locked.get();
-        assert!(!*locked, "cannot recursively acquire mutex");
-        *locked = true;
+        assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
     }
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        *self.locked.get() = false;
+        self.locked.set(false);
     }
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        let locked = self.locked.get();
-        if *locked {
-            false
-        } else {
-            *locked = true;
-            true
-        }
+        self.locked.replace(true) == false
     }
 
     #[inline]
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 7156c9a..3ede229 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -1,10 +1,12 @@
 use crate::ffi::OsStr;
 use crate::fmt;
 use crate::io;
+use crate::marker::PhantomData;
+use crate::path::Path;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
+use crate::sys_common::process::{CommandEnv, CommandEnvs};
 
 pub use crate::ffi::OsString as EnvKey;
 
@@ -49,6 +51,22 @@
 
     pub fn stderr(&mut self, _stderr: Stdio) {}
 
+    pub fn get_program(&self) -> &OsStr {
+        panic!("unsupported")
+    }
+
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        CommandArgs { _p: PhantomData }
+    }
+
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        self.env.iter()
+    }
+
+    pub fn get_current_dir(&self) -> Option<&Path> {
+        None
+    }
+
     pub fn spawn(
         &mut self,
         _default: Stdio,
@@ -147,3 +165,22 @@
         match self.0 {}
     }
 }
+
+pub struct CommandArgs<'a> {
+    _p: PhantomData<&'a ()>,
+}
+
+impl<'a> Iterator for CommandArgs<'a> {
+    type Item = &'a OsStr;
+    fn next(&mut self) -> Option<&'a OsStr> {
+        None
+    }
+}
+
+impl<'a> ExactSizeIterator for CommandArgs<'a> {}
+
+impl<'a> fmt::Debug for CommandArgs<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().finish()
+    }
+}
diff --git a/library/std/src/sys/unsupported/rwlock.rs b/library/std/src/sys/unsupported/rwlock.rs
index d37f34a..6982b2b 100644
--- a/library/std/src/sys/unsupported/rwlock.rs
+++ b/library/std/src/sys/unsupported/rwlock.rs
@@ -1,7 +1,8 @@
-use crate::cell::UnsafeCell;
+use crate::cell::Cell;
 
 pub struct RWLock {
-    mode: UnsafeCell<isize>,
+    // This platform has no threads, so we can use a Cell here.
+    mode: Cell<isize>,
 }
 
 unsafe impl Send for RWLock {}
@@ -9,14 +10,14 @@
 
 impl RWLock {
     pub const fn new() -> RWLock {
-        RWLock { mode: UnsafeCell::new(0) }
+        RWLock { mode: Cell::new(0) }
     }
 
     #[inline]
     pub unsafe fn read(&self) {
-        let mode = self.mode.get();
-        if *mode >= 0 {
-            *mode += 1;
+        let m = self.mode.get();
+        if m >= 0 {
+            self.mode.set(m + 1);
         } else {
             rtabort!("rwlock locked for writing");
         }
@@ -24,9 +25,9 @@
 
     #[inline]
     pub unsafe fn try_read(&self) -> bool {
-        let mode = self.mode.get();
-        if *mode >= 0 {
-            *mode += 1;
+        let m = self.mode.get();
+        if m >= 0 {
+            self.mode.set(m + 1);
             true
         } else {
             false
@@ -35,19 +36,15 @@
 
     #[inline]
     pub unsafe fn write(&self) {
-        let mode = self.mode.get();
-        if *mode == 0 {
-            *mode = -1;
-        } else {
+        if self.mode.replace(-1) != 0 {
             rtabort!("rwlock locked for reading")
         }
     }
 
     #[inline]
     pub unsafe fn try_write(&self) -> bool {
-        let mode = self.mode.get();
-        if *mode == 0 {
-            *mode = -1;
+        if self.mode.get() == 0 {
+            self.mode.set(-1);
             true
         } else {
             false
@@ -56,12 +53,12 @@
 
     #[inline]
     pub unsafe fn read_unlock(&self) {
-        *self.mode.get() -= 1;
+        self.mode.set(self.mode.get() - 1);
     }
 
     #[inline]
     pub unsafe fn write_unlock(&self) {
-        *self.mode.get() += 1;
+        assert_eq!(self.mode.replace(0), -1);
     }
 
     #[inline]
diff --git a/library/std/src/sys/vxworks/alloc.rs b/library/std/src/sys/vxworks/alloc.rs
deleted file mode 100644
index 97a191d..0000000
--- a/library/std/src/sys/vxworks/alloc.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use crate::alloc::{GlobalAlloc, Layout, System};
-use crate::ptr;
-use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-
-#[stable(feature = "alloc_system_type", since = "1.28.0")]
-unsafe impl GlobalAlloc for System {
-    #[inline]
-    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
-            libc::malloc(layout.size()) as *mut u8
-        } else {
-            aligned_malloc(&layout)
-        }
-    }
-
-    #[inline]
-    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
-            libc::calloc(layout.size(), 1) as *mut u8
-        } else {
-            let ptr = self.alloc(layout.clone());
-            if !ptr.is_null() {
-                ptr::write_bytes(ptr, 0, layout.size());
-            }
-            ptr
-        }
-    }
-
-    #[inline]
-    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
-        libc::free(ptr as *mut libc::c_void)
-    }
-
-    #[inline]
-    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
-            libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
-        } else {
-            realloc_fallback(self, ptr, layout, new_size)
-        }
-    }
-}
-
-#[inline]
-unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-    let mut out = ptr::null_mut();
-    let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
-    if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
-}
diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs
deleted file mode 100644
index adff6c4..0000000
--- a/library/std/src/sys/vxworks/args.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-#![allow(dead_code)] // runtime init functions not used during testing
-use crate::ffi::OsString;
-use crate::marker::PhantomData;
-use crate::vec;
-
-/// One-time global initialization.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
-    imp::init(argc, argv)
-}
-
-/// One-time global cleanup.
-pub unsafe fn cleanup() {
-    imp::cleanup()
-}
-
-/// Returns the command line arguments
-pub fn args() -> Args {
-    imp::args()
-}
-
-pub struct Args {
-    iter: vec::IntoIter<OsString>,
-    _dont_send_or_sync_me: PhantomData<*mut ()>,
-}
-
-impl Args {
-    pub fn inner_debug(&self) -> &[OsString] {
-        self.iter.as_slice()
-    }
-}
-
-impl Iterator for Args {
-    type Item = OsString;
-    fn next(&mut self) -> Option<OsString> {
-        self.iter.next()
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize {
-        self.iter.len()
-    }
-}
-
-impl DoubleEndedIterator for Args {
-    fn next_back(&mut self) -> Option<OsString> {
-        self.iter.next_back()
-    }
-}
-
-mod imp {
-    use super::Args;
-    use crate::ffi::{CStr, OsString};
-    use crate::marker::PhantomData;
-    use crate::ptr;
-
-    use crate::sys_common::mutex::Mutex;
-
-    static mut ARGC: isize = 0;
-    static mut ARGV: *const *const u8 = ptr::null();
-    static LOCK: Mutex = Mutex::new();
-
-    pub unsafe fn init(argc: isize, argv: *const *const u8) {
-        let _guard = LOCK.lock();
-        ARGC = argc;
-        ARGV = argv;
-    }
-
-    pub unsafe fn cleanup() {
-        let _guard = LOCK.lock();
-        ARGC = 0;
-        ARGV = ptr::null();
-    }
-
-    pub fn args() -> Args {
-        Args { iter: clone().into_iter(), _dont_send_or_sync_me: PhantomData }
-    }
-
-    fn clone() -> Vec<OsString> {
-        unsafe {
-            let _guard = LOCK.lock();
-            let ret = (0..ARGC)
-                .map(|i| {
-                    let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
-                    use crate::sys::vxworks::ext::ffi::OsStringExt;
-                    OsStringExt::from_vec(cstr.to_bytes().to_vec())
-                })
-                .collect();
-            return ret;
-        }
-    }
-}
diff --git a/library/std/src/sys/vxworks/cmath.rs b/library/std/src/sys/vxworks/cmath.rs
deleted file mode 100644
index f327b69..0000000
--- a/library/std/src/sys/vxworks/cmath.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-#![cfg(not(test))]
-
-use libc::{c_double, c_float};
-
-extern "C" {
-    pub fn acos(n: c_double) -> c_double;
-    pub fn acosf(n: c_float) -> c_float;
-    pub fn asin(n: c_double) -> c_double;
-    pub fn asinf(n: c_float) -> c_float;
-    pub fn atan(n: c_double) -> c_double;
-    pub fn atan2(a: c_double, b: c_double) -> c_double;
-    pub fn atan2f(a: c_float, b: c_float) -> c_float;
-    pub fn atanf(n: c_float) -> c_float;
-    pub fn cbrt(n: c_double) -> c_double;
-    pub fn cbrtf(n: c_float) -> c_float;
-    pub fn cosh(n: c_double) -> c_double;
-    pub fn coshf(n: c_float) -> c_float;
-    pub fn expm1(n: c_double) -> c_double;
-    pub fn expm1f(n: c_float) -> c_float;
-    pub fn fdim(a: c_double, b: c_double) -> c_double;
-    pub fn fdimf(a: c_float, b: c_float) -> c_float;
-    pub fn hypot(x: c_double, y: c_double) -> c_double;
-    pub fn hypotf(x: c_float, y: c_float) -> c_float;
-    pub fn log1p(n: c_double) -> c_double;
-    pub fn log1pf(n: c_float) -> c_float;
-    pub fn sinh(n: c_double) -> c_double;
-    pub fn sinhf(n: c_float) -> c_float;
-    pub fn tan(n: c_double) -> c_double;
-    pub fn tanf(n: c_float) -> c_float;
-    pub fn tanh(n: c_double) -> c_double;
-    pub fn tanhf(n: c_float) -> c_float;
-}
diff --git a/library/std/src/sys/vxworks/condvar.rs b/library/std/src/sys/vxworks/condvar.rs
deleted file mode 100644
index 5a77966..0000000
--- a/library/std/src/sys/vxworks/condvar.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sys::mutex::{self, Mutex};
-use crate::time::Duration;
-
-pub struct Condvar {
-    inner: UnsafeCell<libc::pthread_cond_t>,
-}
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
-const TIMESPEC_MAX: libc::timespec =
-    libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
-
-fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
-    if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t }
-}
-
-impl Condvar {
-    pub const fn new() -> Condvar {
-        // Might be moved and address is changing it is better to avoid
-        // initialization of potentially opaque OS data before it landed
-        Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) }
-    }
-
-    pub unsafe fn init(&mut self) {
-        use crate::mem::MaybeUninit;
-        let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
-        let r = libc::pthread_condattr_init(attr.as_mut_ptr());
-        assert_eq!(r, 0);
-        let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
-        assert_eq!(r, 0);
-        let r = libc::pthread_cond_init(self.inner.get(), attr.as_ptr());
-        assert_eq!(r, 0);
-        let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
-        assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub unsafe fn notify_one(&self) {
-        let r = libc::pthread_cond_signal(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub unsafe fn notify_all(&self) {
-        let r = libc::pthread_cond_broadcast(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        let r = libc::pthread_cond_wait(self.inner.get(), mutex::raw(mutex));
-        debug_assert_eq!(r, 0);
-    }
-
-    // This implementation is used on systems that support pthread_condattr_setclock
-    // where we configure condition variable to use monotonic clock (instead of
-    // default system clock). This approach avoids all problems that result
-    // from changes made to the system time.
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        use crate::mem;
-
-        let mut now: libc::timespec = mem::zeroed();
-        let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now);
-        assert_eq!(r, 0);
-
-        // Nanosecond calculations can't overflow because both values are below 1e9.
-        let nsec = dur.subsec_nanos() + now.tv_nsec as u32;
-
-        let sec = saturating_cast_to_time_t(dur.as_secs())
-            .checked_add((nsec / 1_000_000_000) as libc::time_t)
-            .and_then(|s| s.checked_add(now.tv_sec));
-        let nsec = nsec % 1_000_000_000;
-
-        let timeout =
-            sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX);
-
-        let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout);
-        assert!(r == libc::ETIMEDOUT || r == 0);
-        r == 0
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        let r = libc::pthread_cond_destroy(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-}
diff --git a/library/std/src/sys/vxworks/ext/ffi.rs b/library/std/src/sys/vxworks/ext/ffi.rs
deleted file mode 100644
index 76b34a6..0000000
--- a/library/std/src/sys/vxworks/ext/ffi.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-//! Unix-specific extension to the primitives in the `std::ffi` module
-//!
-//! # Examples
-//!
-//! ```
-//! use std::ffi::OsString;
-//! use std::os::unix::ffi::OsStringExt;
-//!
-//! let bytes = b"foo".to_vec();
-//!
-//! // OsStringExt::from_vec
-//! let os_string = OsString::from_vec(bytes);
-//! assert_eq!(os_string.to_str(), Some("foo"));
-//!
-//! // OsStringExt::into_vec
-//! let bytes = os_string.into_vec();
-//! assert_eq!(bytes, b"foo");
-//! ```
-//!
-//! ```
-//! use std::ffi::OsStr;
-//! use std::os::unix::ffi::OsStrExt;
-//!
-//! let bytes = b"foo";
-//!
-//! // OsStrExt::from_bytes
-//! let os_str = OsStr::from_bytes(bytes);
-//! assert_eq!(os_str.to_str(), Some("foo"));
-//!
-//! // OsStrExt::as_bytes
-//! let bytes = os_str.as_bytes();
-//! assert_eq!(bytes, b"foo");
-//! ```
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/sys/vxworks/ext/fs.rs b/library/std/src/sys/vxworks/ext/fs.rs
deleted file mode 100644
index 68dc21b..0000000
--- a/library/std/src/sys/vxworks/ext/fs.rs
+++ /dev/null
@@ -1,817 +0,0 @@
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::fs::{self, Permissions};
-use crate::io;
-use crate::path::Path;
-use crate::sys;
-use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-
-/// Unix-specific extensions to [`fs::File`].
-#[stable(feature = "file_offset", since = "1.15.0")]
-pub trait FileExt {
-    /// Reads a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes read.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// Note that similar to [`File::read`], it is not an error to return with a
-    /// short read.
-    ///
-    /// [`File::read`]: fs::File::read
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs::File;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let mut buf = [0u8; 8];
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now read 8 bytes from the offset 10.
-    ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
-    ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
-
-    /// Reads the exact number of byte required to fill `buf` from the given offset.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
-    ///
-    /// [`Read::read_exact`]: io::Read::read_exact
-    /// [`read_at`]: FileExt::read_at
-    ///
-    /// # Errors
-    ///
-    /// If this function encounters an error of the kind
-    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
-    /// will continue.
-    ///
-    /// If this function encounters an "end of file" before completely filling
-    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
-    /// The contents of `buf` are unspecified in this case.
-    ///
-    /// If any other read error is encountered then this function immediately
-    /// returns. The contents of `buf` are unspecified in this case.
-    ///
-    /// If this function returns an error, it is unspecified how many bytes it
-    /// has read, but it will never read more than would be necessary to
-    /// completely fill the buffer.
-    ///
-    /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted
-    /// [`ErrorKind::UnexpectedEof`]: io::ErrorKind::UnexpectedEof
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(rw_exact_all_at)]
-    /// use std::io;
-    /// use std::fs::File;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let mut buf = [0u8; 8];
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now read exactly 8 bytes from the offset 10.
-    ///     file.read_exact_at(&mut buf, 10)?;
-    ///     println!("read {} bytes: {:?}", buf.len(), buf);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
-    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
-        while !buf.is_empty() {
-            match self.read_at(buf, offset) {
-                Ok(0) => break,
-                Ok(n) => {
-                    let tmp = buf;
-                    buf = &mut tmp[n..];
-                    offset += n as u64;
-                }
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        if !buf.is_empty() {
-            Err(io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
-        } else {
-            Ok(())
-        }
-    }
-
-    /// Writes a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes written.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// When writing beyond the end of the file, the file is appropriately
-    /// extended and the intermediate bytes are initialized with the value 0.
-    ///
-    /// Note that similar to [`File::write`], it is not an error to return a
-    /// short write.
-    ///
-    /// [`File::write`]: fs::File::write
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now write at the offset 10.
-    ///     file.write_at(b"sushi", 10)?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
-
-    /// Attempts to write an entire buffer starting from a given offset.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// This method will continuously call [`write_at`] until there is no more data
-    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
-    /// returned. This method will not return until the entire buffer has been
-    /// successfully written or such an error occurs. The first error that is
-    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
-    /// returned.
-    ///
-    /// # Errors
-    ///
-    /// This function will return the first error of
-    /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
-    ///
-    /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted
-    /// [`write_at`]: FileExt::write_at
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(rw_exact_all_at)]
-    /// use std::fs::File;
-    /// use std::io;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now write at the offset 10.
-    ///     file.write_all_at(b"sushi", 10)?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
-    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
-        while !buf.is_empty() {
-            match self.write_at(buf, offset) {
-                Ok(0) => {
-                    return Err(io::Error::new(
-                        io::ErrorKind::WriteZero,
-                        "failed to write whole buffer",
-                    ));
-                }
-                Ok(n) => {
-                    buf = &buf[n..];
-                    offset += n as u64
-                }
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        Ok(())
-    }
-}
-
-#[stable(feature = "file_offset", since = "1.15.0")]
-impl FileExt for fs::File {
-    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        self.as_inner().read_at(buf, offset)
-    }
-    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        self.as_inner().write_at(buf, offset)
-    }
-}
-
-/// Unix-specific extensions to [`fs::Permissions`].
-#[stable(feature = "fs_ext", since = "1.1.0")]
-pub trait PermissionsExt {
-    /// Returns the underlying raw `st_mode` bits that contain the standard
-    /// Unix permissions for this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::os::unix::fs::PermissionsExt;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::create("foo.txt")?;
-    ///     let metadata = f.metadata()?;
-    ///     let permissions = metadata.permissions();
-    ///
-    ///     println!("permissions: {}", permissions.mode());
-    ///     Ok(()) }
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn mode(&self) -> u32;
-
-    /// Sets the underlying raw bits for this set of permissions.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::os::unix::fs::PermissionsExt;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::create("foo.txt")?;
-    ///     let metadata = f.metadata()?;
-    ///     let mut permissions = metadata.permissions();
-    ///
-    ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
-    ///     assert_eq!(permissions.mode(), 0o644);
-    ///     Ok(()) }
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn set_mode(&mut self, mode: u32);
-
-    /// Creates a new instance of `Permissions` from the given set of Unix
-    /// permission bits.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::fs::Permissions;
-    /// use std::os::unix::fs::PermissionsExt;
-    ///
-    /// // Read/write for owner and read for others.
-    /// let permissions = Permissions::from_mode(0o644);
-    /// assert_eq!(permissions.mode(), 0o644);
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn from_mode(mode: u32) -> Self;
-}
-
-#[stable(feature = "fs_ext", since = "1.1.0")]
-impl PermissionsExt for Permissions {
-    fn mode(&self) -> u32 {
-        self.as_inner().mode()
-    }
-
-    fn set_mode(&mut self, mode: u32) {
-        *self = Permissions::from_inner(FromInner::from_inner(mode));
-    }
-
-    fn from_mode(mode: u32) -> Permissions {
-        Permissions::from_inner(FromInner::from_inner(mode))
-    }
-}
-
-/// Unix-specific extensions to [`fs::OpenOptions`].
-#[stable(feature = "fs_ext", since = "1.1.0")]
-pub trait OpenOptionsExt {
-    /// Sets the mode bits that a new file will be created with.
-    ///
-    /// If a new file is created as part of an `OpenOptions::open` call then this
-    /// specified `mode` will be used as the permission bits for the new file.
-    /// If no `mode` is set, the default of `0o666` will be used.
-    /// The operating system masks out bits with the system's `umask`, to produce
-    /// the final permissions.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::OpenOptions;
-    /// use std::os::unix::fs::OpenOptionsExt;
-    ///
-    /// # fn main() {
-    /// let mut options = OpenOptions::new();
-    /// options.mode(0o644); // Give read/write for owner and read for others.
-    /// let file = options.open("foo.txt");
-    /// # }
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn mode(&mut self, mode: u32) -> &mut Self;
-
-    /// Pass custom flags to the `flags` argument of `open`.
-    ///
-    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
-    /// ensure they do not interfere with the access mode set by Rusts options.
-    ///
-    /// Custom flags can only set flags, not remove flags set by Rusts options.
-    /// This options overwrites any previously set custom flags.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// # #![feature(libc)]
-    /// extern crate libc;
-    /// use std::fs::OpenOptions;
-    /// use std::os::unix::fs::OpenOptionsExt;
-    ///
-    /// # fn main() {
-    /// let mut options = OpenOptions::new();
-    /// options.write(true);
-    /// if cfg!(unix) {
-    ///     options.custom_flags(libc::O_NOFOLLOW);
-    /// }
-    /// let file = options.open("foo.txt");
-    /// # }
-    /// ```
-    #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn custom_flags(&mut self, flags: i32) -> &mut Self;
-}
-
-/*#[stable(feature = "fs_ext", since = "1.1.0")]
-impl OpenOptionsExt for OpenOptions {
-    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
-        self.as_inner_mut().mode(mode); self
-    }
-
-    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
-        self.as_inner_mut().custom_flags(flags); self
-    }
-}
-*/
-
-/// Unix-specific extensions to [`fs::Metadata`].
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Returns the ID of the device containing the file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let dev_id = meta.dev();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn dev(&self) -> u64;
-    /// Returns the inode number.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let inode = meta.ino();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn ino(&self) -> u64;
-    /// Returns the rights applied to this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let mode = meta.mode();
-    ///     let user_has_write_access      = mode & 0o200;
-    ///     let user_has_read_write_access = mode & 0o600;
-    ///     let group_has_read_access      = mode & 0o040;
-    ///     let others_have_exec_access    = mode & 0o001;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn mode(&self) -> u32;
-    /// Returns the number of hard links pointing to this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nb_hard_links = meta.nlink();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn nlink(&self) -> u64;
-    /// Returns the user ID of the owner of this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let user_id = meta.uid();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn uid(&self) -> u32;
-    /// Returns the group ID of the owner of this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let group_id = meta.gid();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn gid(&self) -> u32;
-    /// Returns the device ID of this file (if it is a special one).
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let device_id = meta.rdev();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn rdev(&self) -> u64;
-    /// Returns the total size of this file in bytes.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let file_size = meta.size();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn size(&self) -> u64;
-    /// Returns the time of the last access to the file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let last_access_time = meta.atime();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn atime(&self) -> i64;
-    /// Returns the time of the last access to the file in nanoseconds.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nano_last_access_time = meta.atime_nsec();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn mtime(&self) -> i64;
-    /// Returns the time of the last modification of the file in nanoseconds.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nano_last_modification_time = meta.mtime_nsec();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn ctime(&self) -> i64;
-    /// Returns the time of the last status change of the file in nanoseconds.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nano_last_status_change_time = meta.ctime_nsec();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn blksize(&self) -> u64;
-    /// Returns the number of blocks allocated to the file, in 512-byte units.
-    ///
-    /// Please note that this may be smaller than `st_size / 512` when the file has holes.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let blocks = meta.blocks();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn blocks(&self) -> u64;
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn attrib(&self) -> u8;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for fs::Metadata {
-    fn dev(&self) -> u64 {
-        self.st_dev()
-    }
-    fn ino(&self) -> u64 {
-        self.st_ino()
-    }
-    fn mode(&self) -> u32 {
-        self.st_mode()
-    }
-    fn nlink(&self) -> u64 {
-        self.st_nlink()
-    }
-    fn uid(&self) -> u32 {
-        self.st_uid()
-    }
-    fn gid(&self) -> u32 {
-        self.st_gid()
-    }
-    fn rdev(&self) -> u64 {
-        self.st_rdev()
-    }
-    fn size(&self) -> u64 {
-        self.st_size()
-    }
-    fn atime(&self) -> i64 {
-        self.st_atime()
-    }
-    fn mtime(&self) -> i64 {
-        self.st_mtime()
-    }
-    fn ctime(&self) -> i64 {
-        self.st_ctime()
-    }
-    fn blksize(&self) -> u64 {
-        self.st_blksize()
-    }
-    fn blocks(&self) -> u64 {
-        self.st_blocks()
-    }
-    fn attrib(&self) -> u8 {
-        self.st_attrib()
-    }
-}
-
-/// Unix-specific extensions for [`fs::FileType`].
-///
-/// Adds support for special Unix file types such as block/character devices,
-/// pipes, and sockets.
-#[stable(feature = "file_type_ext", since = "1.5.0")]
-pub trait FileTypeExt {
-    /// Returns whether this file type is a block device.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("block_device_file")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_block_device());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_block_device(&self) -> bool;
-    /// Returns whether this file type is a char device.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("char_device_file")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_char_device());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_char_device(&self) -> bool;
-    /// Returns whether this file type is a fifo.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("fifo_file")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_fifo());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_fifo(&self) -> bool;
-    /// Returns whether this file type is a socket.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("unix.socket")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_socket());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_socket(&self) -> bool;
-}
-
-#[stable(feature = "file_type_ext", since = "1.5.0")]
-impl FileTypeExt for fs::FileType {
-    fn is_block_device(&self) -> bool {
-        self.as_inner().is(libc::S_IFBLK)
-    }
-    fn is_char_device(&self) -> bool {
-        self.as_inner().is(libc::S_IFCHR)
-    }
-    fn is_fifo(&self) -> bool {
-        self.as_inner().is(libc::S_IFIFO)
-    }
-    fn is_socket(&self) -> bool {
-        self.as_inner().is(libc::S_IFSOCK)
-    }
-}
-
-/// Unix-specific extension methods for [`fs::DirEntry`].
-#[stable(feature = "dir_entry_ext", since = "1.1.0")]
-pub trait DirEntryExt {
-    /// Returns the underlying `d_ino` field in the contained `dirent`
-    /// structure.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::fs;
-    /// use std::os::unix::fs::DirEntryExt;
-    ///
-    /// if let Ok(entries) = fs::read_dir(".") {
-    ///     for entry in entries {
-    ///         if let Ok(entry) = entry {
-    ///             // Here, `entry` is a `DirEntry`.
-    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
-    ///         }
-    ///     }
-    /// }
-    /// ```
-    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
-    fn ino(&self) -> u64;
-}
-
-#[stable(feature = "dir_entry_ext", since = "1.1.0")]
-impl DirEntryExt for fs::DirEntry {
-    fn ino(&self) -> u64 {
-        self.as_inner().ino()
-    }
-}
-
-/// Creates a new symbolic link on the filesystem.
-///
-/// The `dst` path will be a symbolic link pointing to the `src` path.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::unix::fs;
-///
-/// fn main() -> std::io::Result<()> {
-///     fs::symlink("a.txt", "b.txt")?;
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
-    sys::fs::symlink(src.as_ref(), dst.as_ref())
-}
-
-/// Unix-specific extensions to [`fs::DirBuilder`].
-#[stable(feature = "dir_builder", since = "1.6.0")]
-pub trait DirBuilderExt {
-    /// Sets the mode to create new directories with. This option defaults to
-    /// 0o777.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::DirBuilder;
-    /// use std::os::unix::fs::DirBuilderExt;
-    ///
-    /// let mut builder = DirBuilder::new();
-    /// builder.mode(0o755);
-    /// ```
-    #[stable(feature = "dir_builder", since = "1.6.0")]
-    fn mode(&mut self, mode: u32) -> &mut Self;
-}
-
-#[stable(feature = "dir_builder", since = "1.6.0")]
-impl DirBuilderExt for fs::DirBuilder {
-    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
-        self.as_inner_mut().set_mode(mode);
-        self
-    }
-}
diff --git a/library/std/src/sys/vxworks/ext/io.rs b/library/std/src/sys/vxworks/ext/io.rs
deleted file mode 100644
index 25c6e26..0000000
--- a/library/std/src/sys/vxworks/ext/io.rs
+++ /dev/null
@@ -1,189 +0,0 @@
-//! Unix-specific extensions to general I/O primitives
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::fs;
-use crate::io;
-use crate::net;
-use crate::os::raw;
-use crate::sys;
-use crate::sys_common::{self, AsInner, FromInner, IntoInner};
-
-/// Raw file descriptors.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub type RawFd = raw::c_int;
-
-/// A trait to extract the raw unix file descriptor from an underlying
-/// object.
-///
-/// This is only available on unix platforms and must be imported in order
-/// to call the method. Windows platforms have a corresponding `AsRawHandle`
-/// and `AsRawSocket` set of traits.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait AsRawFd {
-    /// Extracts the raw file descriptor.
-    ///
-    /// This method does **not** pass ownership of the raw file descriptor
-    /// to the caller. The descriptor is only guaranteed to be valid while
-    /// the original object has not yet been destroyed.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn as_raw_fd(&self) -> RawFd;
-}
-
-/// A trait to express the ability to construct an object from a raw file
-/// descriptor.
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-pub trait FromRawFd {
-    /// Constructs a new instance of `Self` from the given raw file
-    /// descriptor.
-    ///
-    /// This function **consumes ownership** of the specified file
-    /// descriptor. The returned object will take responsibility for closing
-    /// it when the object goes out of scope.
-    ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
-    #[stable(feature = "from_raw_os", since = "1.1.0")]
-    unsafe fn from_raw_fd(fd: RawFd) -> Self;
-}
-
-/// A trait to express the ability to consume an object and acquire ownership of
-/// its raw file descriptor.
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-pub trait IntoRawFd {
-    /// Consumes this object, returning the raw underlying file descriptor.
-    ///
-    /// This function **transfers ownership** of the underlying file descriptor
-    /// to the caller. Callers are then the unique owners of the file descriptor
-    /// and must close the descriptor once it's no longer needed.
-    #[stable(feature = "into_raw_os", since = "1.4.0")]
-    fn into_raw_fd(self) -> RawFd;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for fs::File {
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for fs::File {
-    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
-        fs::File::from_inner(sys::fs::File::from_inner(fd))
-    }
-}
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for fs::File {
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawFd for io::Stdin {
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawFd for io::Stdout {
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawFd for io::Stderr {
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawFd for io::StdinLock<'a> {
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawFd for io::StdoutLock<'a> {
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawFd for io::StderrLock<'a> {
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for net::TcpStream {
-    fn as_raw_fd(&self) -> RawFd {
-        *self.as_inner().socket().as_inner()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for net::TcpListener {
-    fn as_raw_fd(&self) -> RawFd {
-        *self.as_inner().socket().as_inner()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for net::UdpSocket {
-    fn as_raw_fd(&self) -> RawFd {
-        *self.as_inner().socket().as_inner()
-    }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for net::TcpStream {
-    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
-        let socket = sys::net::Socket::from_inner(fd);
-        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
-    }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for net::TcpListener {
-    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
-        let socket = sys::net::Socket::from_inner(fd);
-        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
-    }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for net::UdpSocket {
-    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
-        let socket = sys::net::Socket::from_inner(fd);
-        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for net::TcpStream {
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_socket().into_inner()
-    }
-}
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for net::TcpListener {
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_socket().into_inner()
-    }
-}
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for net::UdpSocket {
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_socket().into_inner()
-    }
-}
diff --git a/library/std/src/sys/vxworks/ext/mod.rs b/library/std/src/sys/vxworks/ext/mod.rs
deleted file mode 100644
index 8fa9bd9..0000000
--- a/library/std/src/sys/vxworks/ext/mod.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-#![stable(feature = "rust1", since = "1.0.0")]
-#![allow(missing_docs)]
-
-pub mod ffi;
-pub mod fs;
-pub mod io;
-pub mod process;
-pub mod raw;
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::process::ExitStatusExt;
-}
diff --git a/library/std/src/sys/vxworks/ext/process.rs b/library/std/src/sys/vxworks/ext/process.rs
deleted file mode 100644
index 3ffa5be..0000000
--- a/library/std/src/sys/vxworks/ext/process.rs
+++ /dev/null
@@ -1,229 +0,0 @@
-//! Unix-specific extensions to primitives in the `std::process` module.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::ffi::OsStr;
-use crate::io;
-use crate::process;
-use crate::sys;
-use crate::sys::vxworks::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-
-/// Unix-specific extensions to the [`process::Command`] builder.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait CommandExt {
-    /// Sets the child process's user ID. This translates to a
-    /// `setuid` call in the child process. Failure in the `setuid`
-    /// call will cause the spawn to fail.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn uid(&mut self, id: u16) -> &mut process::Command;
-
-    /// Similar to `uid`, but sets the group ID of the child process. This has
-    /// the same semantics as the `uid` field.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn gid(&mut self, id: u16) -> &mut process::Command;
-
-    /// Schedules a closure to be run just before the `exec` function is
-    /// invoked.
-    ///
-    /// The closure is allowed to return an I/O error whose OS error code will
-    /// be communicated back to the parent and returned as an error from when
-    /// the spawn was requested.
-    ///
-    /// Multiple closures can be registered and they will be called in order of
-    /// their registration. If a closure returns `Err` then no further closures
-    /// will be called and the spawn operation will immediately return with a
-    /// failure.
-    ///
-    /// # Notes and Safety
-    ///
-    /// This closure will be run in the context of the child process after a
-    /// `fork`. This primarily means that any modifications made to memory on
-    /// behalf of this closure will **not** be visible to the parent process.
-    /// This is often a very constrained environment where normal operations
-    /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
-    /// other threads perhaps still running when the `fork` was run).
-    ///
-    /// This also means that all resources such as file descriptors and
-    /// memory-mapped regions got duplicated. It is your responsibility to make
-    /// sure that the closure does not violate library invariants by making
-    /// invalid use of these duplicates.
-    ///
-    /// When this closure is run, aspects such as the stdio file descriptors and
-    /// working directory have successfully been changed, so output to these
-    /// locations may not appear where intended.
-    #[stable(feature = "process_pre_exec", since = "1.34.0")]
-    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
-    where
-        F: FnMut() -> io::Result<()> + Send + Sync + 'static;
-
-    /// Schedules a closure to be run just before the `exec` function is
-    /// invoked.
-    ///
-    /// This method is stable and usable, but it should be unsafe. To fix
-    /// that, it got deprecated in favor of the unsafe [`pre_exec`].
-    ///
-    /// [`pre_exec`]: CommandExt::pre_exec
-    #[stable(feature = "process_exec", since = "1.15.0")]
-    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
-    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
-    where
-        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
-    {
-        unsafe { self.pre_exec(f) }
-    }
-
-    /// Performs all the required setup by this `Command`, followed by calling
-    /// the `execvp` syscall.
-    ///
-    /// On success this function will not return, and otherwise it will return
-    /// an error indicating why the exec (or another part of the setup of the
-    /// `Command`) failed.
-    ///
-    /// `exec` not returning has the same implications as calling
-    /// [`process::exit`] – no destructors on the current stack or any other
-    /// thread’s stack will be run. Therefore, it is recommended to only call
-    /// `exec` at a point where it is fine to not run any destructors. Note,
-    /// that the `execvp` syscall independently guarantees that all memory is
-    /// freed and all file descriptors with the `CLOEXEC` option (set by default
-    /// on all file descriptors opened by the standard library) are closed.
-    ///
-    /// This function, unlike `spawn`, will **not** `fork` the process to create
-    /// a new child. Like spawn, however, the default behavior for the stdio
-    /// descriptors will be to inherited from the current process.
-    ///
-    ///
-    /// # Notes
-    ///
-    /// The process may be in a "broken state" if this function returns in
-    /// error. For example the working directory, environment variables, signal
-    /// handling settings, various user/group information, or aspects of stdio
-    /// file descriptors may have changed. If a "transactional spawn" is
-    /// required to gracefully handle errors it is recommended to use the
-    /// cross-platform `spawn` instead.
-    #[stable(feature = "process_exec2", since = "1.9.0")]
-    fn exec(&mut self) -> io::Error;
-
-    /// Set executable argument
-    ///
-    /// Set the first process argument, `argv[0]`, to something other than the
-    /// default executable path.
-    #[stable(feature = "process_set_argv0", since = "1.45.0")]
-    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
-    where
-        S: AsRef<OsStr>;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl CommandExt for process::Command {
-    fn uid(&mut self, id: u16) -> &mut process::Command {
-        self.as_inner_mut().uid(id);
-        self
-    }
-
-    fn gid(&mut self, id: u16) -> &mut process::Command {
-        self.as_inner_mut().gid(id);
-        self
-    }
-
-    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
-    where
-        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
-    {
-        self.as_inner_mut().pre_exec(Box::new(f));
-        self
-    }
-
-    fn exec(&mut self) -> io::Error {
-        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
-    }
-
-    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
-    where
-        S: AsRef<OsStr>,
-    {
-        self.as_inner_mut().set_arg_0(arg.as_ref());
-        self
-    }
-}
-
-/// Unix-specific extensions to [`process::ExitStatus`].
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait ExitStatusExt {
-    /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
-    /// a process.
-    #[stable(feature = "exit_status_from", since = "1.12.0")]
-    fn from_raw(raw: i32) -> Self;
-
-    /// If the process was terminated by a signal, returns that signal.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn signal(&self) -> Option<i32>;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl ExitStatusExt for process::ExitStatus {
-    fn from_raw(raw: i32) -> Self {
-        process::ExitStatus::from_inner(From::from(raw))
-    }
-
-    fn signal(&self) -> Option<i32> {
-        self.as_inner().signal()
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl FromRawFd for process::Stdio {
-    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
-        let fd = sys::fd::FileDesc::new(fd);
-        let io = sys::process::Stdio::Fd(fd);
-        process::Stdio::from_inner(io)
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawFd for process::ChildStdin {
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawFd for process::ChildStdout {
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawFd for process::ChildStderr {
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for process::ChildStdin {
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for process::ChildStdout {
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for process::ChildStderr {
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-/// Returns the OS-assigned process identifier associated with this process's parent.
-#[stable(feature = "unix_ppid", since = "1.27.0")]
-pub fn parent_id() -> u32 {
-    crate::sys::os::getppid()
-}
diff --git a/library/std/src/sys/vxworks/ext/raw.rs b/library/std/src/sys/vxworks/ext/raw.rs
deleted file mode 100644
index 1f134f4..0000000
--- a/library/std/src/sys/vxworks/ext/raw.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-#[doc(inline)]
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub use crate::sys::platform::raw::pthread_t;
diff --git a/library/std/src/sys/vxworks/fd.rs b/library/std/src/sys/vxworks/fd.rs
deleted file mode 100644
index d58468a..0000000
--- a/library/std/src/sys/vxworks/fd.rs
+++ /dev/null
@@ -1,201 +0,0 @@
-#![unstable(reason = "not public", issue = "none", feature = "fd")]
-
-use crate::cmp;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
-use crate::mem;
-use crate::sys::cvt;
-use crate::sys_common::AsInner;
-
-use libc::{self, c_int, c_void, ssize_t};
-
-#[derive(Debug)]
-pub struct FileDesc {
-    fd: c_int,
-}
-
-// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
-// with the man page quoting that if the count of bytes to read is
-// greater than `SSIZE_MAX` the result is "unspecified".
-const READ_LIMIT: usize = ssize_t::MAX as usize;
-
-impl FileDesc {
-    pub fn new(fd: c_int) -> FileDesc {
-        FileDesc { fd: fd }
-    }
-
-    pub fn raw(&self) -> c_int {
-        self.fd
-    }
-
-    /// Extracts the actual file descriptor without closing it.
-    pub fn into_raw(self) -> c_int {
-        let fd = self.fd;
-        mem::forget(self);
-        fd
-    }
-
-    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        let ret = cvt(unsafe {
-            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
-        })?;
-        Ok(ret as usize)
-    }
-
-    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        let ret = cvt(unsafe {
-            libc::readv(
-                self.fd,
-                bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
-            )
-        })?;
-        Ok(ret as usize)
-    }
-
-    #[inline]
-    pub fn is_read_vectored(&self) -> bool {
-        true
-    }
-
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        let mut me = self;
-        (&mut me).read_to_end(buf)
-    }
-
-    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        unsafe fn cvt_pread(
-            fd: c_int,
-            buf: *mut c_void,
-            count: usize,
-            offset: i64,
-        ) -> io::Result<isize> {
-            use libc::pread;
-            cvt(pread(fd, buf, count, offset))
-        }
-
-        unsafe {
-            cvt_pread(
-                self.fd,
-                buf.as_mut_ptr() as *mut c_void,
-                cmp::min(buf.len(), READ_LIMIT),
-                offset as i64,
-            )
-            .map(|n| n as usize)
-        }
-    }
-
-    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        let ret = cvt(unsafe {
-            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
-        })?;
-        Ok(ret as usize)
-    }
-
-    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let ret = cvt(unsafe {
-            libc::writev(
-                self.fd,
-                bufs.as_ptr() as *const libc::iovec,
-                cmp::min(bufs.len(), c_int::MAX as usize) as c_int,
-            )
-        })?;
-        Ok(ret as usize)
-    }
-
-    #[inline]
-    pub fn is_write_vectored(&self) -> bool {
-        true
-    }
-
-    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        unsafe fn cvt_pwrite(
-            fd: c_int,
-            buf: *const c_void,
-            count: usize,
-            offset: i64,
-        ) -> io::Result<isize> {
-            use libc::pwrite;
-            cvt(pwrite(fd, buf, count, offset))
-        }
-
-        unsafe {
-            cvt_pwrite(
-                self.fd,
-                buf.as_ptr() as *const c_void,
-                cmp::min(buf.len(), READ_LIMIT),
-                offset as i64,
-            )
-            .map(|n| n as usize)
-        }
-    }
-
-    pub fn get_cloexec(&self) -> io::Result<bool> {
-        unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
-    }
-
-    pub fn set_cloexec(&self) -> io::Result<()> {
-        unsafe {
-            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
-            let new = previous | libc::FD_CLOEXEC;
-            if new != previous {
-                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
-            }
-            Ok(())
-        }
-    }
-
-    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
-        unsafe {
-            let v = nonblocking as c_int;
-            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
-            Ok(())
-        }
-    }
-
-    // refer to pxPipeDrv library documentation.
-    // VxWorks uses fcntl to set O_NONBLOCK to the pipes
-    pub fn set_nonblocking_pipe(&self, nonblocking: bool) -> io::Result<()> {
-        unsafe {
-            let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?;
-            flags = if nonblocking { flags | libc::O_NONBLOCK } else { flags & !libc::O_NONBLOCK };
-            cvt(libc::fcntl(self.fd, libc::F_SETFL, flags))?;
-            Ok(())
-        }
-    }
-
-    pub fn duplicate(&self) -> io::Result<FileDesc> {
-        let fd = self.raw();
-        match cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) }) {
-            Ok(newfd) => Ok(FileDesc::new(newfd)),
-            Err(e) => return Err(e),
-        }
-    }
-}
-
-impl<'a> Read for &'a FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        (**self).read(buf)
-    }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
-}
-
-impl AsInner<c_int> for FileDesc {
-    fn as_inner(&self) -> &c_int {
-        &self.fd
-    }
-}
-
-impl Drop for FileDesc {
-    fn drop(&mut self) {
-        // Note that errors are ignored when closing a file descriptor. The
-        // reason for this is that if an error occurs we don't actually know if
-        // the file descriptor was closed or not, and if we retried (for
-        // something like EINTR), we might close another valid file descriptor
-        // (opened after we closed ours.
-        let _ = unsafe { libc::close(self.fd) };
-    }
-}
diff --git a/library/std/src/sys/vxworks/fs.rs b/library/std/src/sys/vxworks/fs.rs
deleted file mode 100644
index 557e65c..0000000
--- a/library/std/src/sys/vxworks/fs.rs
+++ /dev/null
@@ -1,625 +0,0 @@
-// copies from linuxx
-use crate::ffi::{CStr, CString, OsStr, OsString};
-use crate::fmt;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
-use crate::mem;
-use crate::path::{Path, PathBuf};
-use crate::ptr;
-use crate::sync::Arc;
-use crate::sys::fd::FileDesc;
-use crate::sys::time::SystemTime;
-use crate::sys::vxworks::ext::ffi::OsStrExt;
-use crate::sys::vxworks::ext::ffi::OsStringExt;
-use crate::sys::{cvt, cvt_r};
-use crate::sys_common::{AsInner, FromInner};
-use libc::{self, c_int, mode_t, off_t, stat64};
-use libc::{dirent, ftruncate, lseek, open, readdir_r as readdir64_r};
-pub struct File(FileDesc);
-
-#[derive(Clone)]
-pub struct FileAttr {
-    stat: stat64,
-}
-
-// all DirEntry's will have a reference to this struct
-struct InnerReadDir {
-    dirp: Dir,
-    root: PathBuf,
-}
-
-#[derive(Clone)]
-pub struct ReadDir {
-    inner: Arc<InnerReadDir>,
-    end_of_stream: bool,
-}
-
-struct Dir(*mut libc::DIR);
-
-unsafe impl Send for Dir {}
-unsafe impl Sync for Dir {}
-
-pub struct DirEntry {
-    entry: dirent,
-    dir: ReadDir,
-}
-
-#[derive(Clone, Debug)]
-pub struct OpenOptions {
-    // generic
-    read: bool,
-    write: bool,
-    append: bool,
-    truncate: bool,
-    create: bool,
-    create_new: bool,
-    // system-specific
-    custom_flags: i32,
-    mode: mode_t,
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct FilePermissions {
-    mode: mode_t,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub struct FileType {
-    mode: mode_t,
-}
-
-#[derive(Debug)]
-pub struct DirBuilder {
-    mode: mode_t,
-}
-
-impl FileAttr {
-    pub fn size(&self) -> u64 {
-        self.stat.st_size as u64
-    }
-    pub fn perm(&self) -> FilePermissions {
-        FilePermissions { mode: (self.stat.st_mode as mode_t) }
-    }
-
-    pub fn file_type(&self) -> FileType {
-        FileType { mode: self.stat.st_mode as mode_t }
-    }
-
-    pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: 0, // hack 2.0;
-        }))
-    }
-
-    pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: 0, // hack - a proper fix would be better
-        }))
-    }
-
-    pub fn created(&self) -> io::Result<SystemTime> {
-        Err(io::Error::new(
-            io::ErrorKind::Other,
-            "creation time is not available on this platform currently",
-        ))
-    }
-}
-
-impl AsInner<stat64> for FileAttr {
-    fn as_inner(&self) -> &stat64 {
-        &self.stat
-    }
-}
-
-impl FilePermissions {
-    pub fn readonly(&self) -> bool {
-        // check if any class (owner, group, others) has write permission
-        self.mode & 0o222 == 0
-    }
-
-    pub fn set_readonly(&mut self, readonly: bool) {
-        if readonly {
-            // remove write permission for all classes; equivalent to `chmod a-w <file>`
-            self.mode &= !0o222;
-        } else {
-            // add write permission for all classes; equivalent to `chmod a+w <file>`
-            self.mode |= 0o222;
-        }
-    }
-    pub fn mode(&self) -> u32 {
-        self.mode as u32
-    }
-}
-
-impl FileType {
-    pub fn is_dir(&self) -> bool {
-        self.is(libc::S_IFDIR)
-    }
-    pub fn is_file(&self) -> bool {
-        self.is(libc::S_IFREG)
-    }
-    pub fn is_symlink(&self) -> bool {
-        self.is(libc::S_IFLNK)
-    }
-
-    pub fn is(&self, mode: mode_t) -> bool {
-        self.mode & libc::S_IFMT == mode
-    }
-}
-
-impl FromInner<u32> for FilePermissions {
-    fn from_inner(mode: u32) -> FilePermissions {
-        FilePermissions { mode: mode as mode_t }
-    }
-}
-
-impl fmt::Debug for ReadDir {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
-        // Thus the result will be e g 'ReadDir("/home")'
-        fmt::Debug::fmt(&*self.inner.root, f)
-    }
-}
-
-impl Iterator for ReadDir {
-    type Item = io::Result<DirEntry>;
-    fn next(&mut self) -> Option<io::Result<DirEntry>> {
-        if self.end_of_stream {
-            return None;
-        }
-
-        unsafe {
-            let mut ret = DirEntry { entry: mem::zeroed(), dir: self.clone() };
-            let mut entry_ptr = ptr::null_mut();
-            loop {
-                if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
-                    if entry_ptr.is_null() {
-                        // We encountered an error (which will be returned in this iteration), but
-                        // we also reached the end of the directory stream. The `end_of_stream`
-                        // flag is enabled to make sure that we return `None` in the next iteration
-                        // (instead of looping forever)
-                        self.end_of_stream = true;
-                    }
-                    return Some(Err(Error::last_os_error()));
-                }
-                if entry_ptr.is_null() {
-                    return None;
-                }
-                if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
-                    return Some(Ok(ret));
-                }
-            }
-        }
-    }
-}
-
-impl Drop for Dir {
-    fn drop(&mut self) {
-        let r = unsafe { libc::closedir(self.0) };
-        debug_assert_eq!(r, 0);
-    }
-}
-
-impl DirEntry {
-    pub fn path(&self) -> PathBuf {
-        use crate::sys::vxworks::ext::ffi::OsStrExt;
-        self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
-    }
-
-    pub fn file_name(&self) -> OsString {
-        OsStr::from_bytes(self.name_bytes()).to_os_string()
-    }
-
-    pub fn metadata(&self) -> io::Result<FileAttr> {
-        lstat(&self.path())
-    }
-
-    pub fn file_type(&self) -> io::Result<FileType> {
-        lstat(&self.path()).map(|m| m.file_type())
-    }
-
-    pub fn ino(&self) -> u64 {
-        self.entry.d_ino as u64
-    }
-
-    fn name_bytes(&self) -> &[u8] {
-        unsafe {
-            //&*self.name
-            CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
-        }
-    }
-}
-
-impl OpenOptions {
-    pub fn new() -> OpenOptions {
-        OpenOptions {
-            // generic
-            read: false,
-            write: false,
-            append: false,
-            truncate: false,
-            create: false,
-            create_new: false,
-            // system-specific
-            custom_flags: 0,
-            mode: 0o666,
-        }
-    }
-
-    pub fn read(&mut self, read: bool) {
-        self.read = read;
-    }
-    pub fn write(&mut self, write: bool) {
-        self.write = write;
-    }
-    pub fn append(&mut self, append: bool) {
-        self.append = append;
-    }
-    pub fn truncate(&mut self, truncate: bool) {
-        self.truncate = truncate;
-    }
-    pub fn create(&mut self, create: bool) {
-        self.create = create;
-    }
-    pub fn create_new(&mut self, create_new: bool) {
-        self.create_new = create_new;
-    }
-    pub fn mode(&mut self, mode: u32) {
-        self.mode = mode as mode_t;
-    }
-
-    fn get_access_mode(&self) -> io::Result<c_int> {
-        match (self.read, self.write, self.append) {
-            (true, false, false) => Ok(libc::O_RDONLY),
-            (false, true, false) => Ok(libc::O_WRONLY),
-            (true, true, false) => Ok(libc::O_RDWR),
-            (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND),
-            (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND),
-            (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
-        }
-    }
-
-    fn get_creation_mode(&self) -> io::Result<c_int> {
-        match (self.write, self.append) {
-            (true, false) => {}
-            (false, false) => {
-                if self.truncate || self.create || self.create_new {
-                    return Err(Error::from_raw_os_error(libc::EINVAL));
-                }
-            }
-            (_, true) => {
-                if self.truncate && !self.create_new {
-                    return Err(Error::from_raw_os_error(libc::EINVAL));
-                }
-            }
-        }
-
-        Ok(match (self.create, self.truncate, self.create_new) {
-            (false, false, false) => 0,
-            (true, false, false) => libc::O_CREAT,
-            (false, true, false) => libc::O_TRUNC,
-            (true, true, false) => libc::O_CREAT | libc::O_TRUNC,
-            (_, _, true) => libc::O_CREAT | libc::O_EXCL,
-        })
-    }
-}
-
-impl File {
-    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
-        let path = cstr(path)?;
-        File::open_c(&path, opts)
-    }
-
-    pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
-        let flags = libc::O_CLOEXEC
-            | opts.get_access_mode()?
-            | opts.get_creation_mode()?
-            | (opts.custom_flags as c_int & !libc::O_ACCMODE);
-        let fd = cvt_r(|| unsafe { open(path.as_ptr(), flags, opts.mode as c_int) })?;
-        Ok(File(FileDesc::new(fd)))
-    }
-
-    pub fn file_attr(&self) -> io::Result<FileAttr> {
-        let mut stat: stat64 = unsafe { mem::zeroed() };
-        cvt(unsafe { ::libc::fstat(self.0.raw(), &mut stat) })?;
-        Ok(FileAttr { stat: stat })
-    }
-
-    pub fn fsync(&self) -> io::Result<()> {
-        cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?;
-        Ok(())
-    }
-
-    pub fn datasync(&self) -> io::Result<()> {
-        cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
-        return Ok(());
-        unsafe fn os_datasync(fd: c_int) -> c_int {
-            libc::fsync(fd)
-        } //not supported
-    }
-
-    pub fn truncate(&self, size: u64) -> io::Result<()> {
-        return cvt_r(|| unsafe { ftruncate(self.0.raw(), size as off_t) }).map(drop);
-    }
-
-    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.0.read(buf)
-    }
-
-    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        self.0.read_vectored(bufs)
-    }
-
-    #[inline]
-    pub fn is_read_vectored(&self) -> bool {
-        self.0.is_read_vectored()
-    }
-
-    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        self.0.read_at(buf, offset)
-    }
-
-    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
-    }
-
-    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        self.0.write_vectored(bufs)
-    }
-
-    #[inline]
-    pub fn is_write_vectored(&self) -> bool {
-        self.0.is_write_vectored()
-    }
-
-    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        self.0.write_at(buf, offset)
-    }
-
-    pub fn flush(&self) -> io::Result<()> {
-        Ok(())
-    }
-
-    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
-        let (whence, pos) = match pos {
-            // Casting to `i64` is fine, too large values will end up as
-            // negative which will cause an error in `"lseek64"`.
-            SeekFrom::Start(off) => (libc::SEEK_SET, off as i64),
-            SeekFrom::End(off) => (libc::SEEK_END, off),
-            SeekFrom::Current(off) => (libc::SEEK_CUR, off),
-        };
-        let n = cvt(unsafe { lseek(self.0.raw(), pos, whence) })?;
-        Ok(n as u64)
-    }
-
-    pub fn duplicate(&self) -> io::Result<File> {
-        self.0.duplicate().map(File)
-    }
-
-    pub fn fd(&self) -> &FileDesc {
-        &self.0
-    }
-
-    pub fn into_fd(self) -> FileDesc {
-        self.0
-    }
-
-    pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
-        cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
-        Ok(())
-    }
-
-    pub fn diverge(&self) -> ! {
-        panic!()
-    }
-}
-
-impl DirBuilder {
-    pub fn new() -> DirBuilder {
-        DirBuilder { mode: 0o777 }
-    }
-
-    pub fn mkdir(&self, p: &Path) -> io::Result<()> {
-        let p = cstr(p)?;
-        cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?;
-        Ok(())
-    }
-
-    pub fn set_mode(&mut self, mode: u32) {
-        self.mode = mode as mode_t;
-    }
-}
-
-fn cstr(path: &Path) -> io::Result<CString> {
-    use crate::sys::vxworks::ext::ffi::OsStrExt;
-    Ok(CString::new(path.as_os_str().as_bytes())?)
-}
-
-impl FromInner<c_int> for File {
-    fn from_inner(fd: c_int) -> File {
-        File(FileDesc::new(fd))
-    }
-}
-
-impl fmt::Debug for File {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fn get_path(fd: c_int) -> Option<PathBuf> {
-            let mut buf = vec![0; libc::PATH_MAX as usize];
-            let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) };
-            if n == -1 {
-                return None;
-            }
-            let l = buf.iter().position(|&c| c == 0).unwrap();
-            buf.truncate(l as usize);
-            Some(PathBuf::from(OsString::from_vec(buf)))
-        }
-        fn get_mode(fd: c_int) -> Option<(bool, bool)> {
-            let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
-            if mode == -1 {
-                return None;
-            }
-            match mode & libc::O_ACCMODE {
-                libc::O_RDONLY => Some((true, false)),
-                libc::O_RDWR => Some((true, true)),
-                libc::O_WRONLY => Some((false, true)),
-                _ => None,
-            }
-        }
-
-        let fd = self.0.raw();
-        let mut b = f.debug_struct("File");
-        b.field("fd", &fd);
-        if let Some(path) = get_path(fd) {
-            b.field("path", &path);
-        }
-        if let Some((read, write)) = get_mode(fd) {
-            b.field("read", &read).field("write", &write);
-        }
-        b.finish()
-    }
-}
-
-pub fn readdir(p: &Path) -> io::Result<ReadDir> {
-    let root = p.to_path_buf();
-    let p = cstr(p)?;
-    unsafe {
-        let ptr = libc::opendir(p.as_ptr());
-        if ptr.is_null() {
-            Err(Error::last_os_error())
-        } else {
-            let inner = InnerReadDir { dirp: Dir(ptr), root };
-            Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false })
-        }
-    }
-}
-
-pub fn unlink(p: &Path) -> io::Result<()> {
-    let p = cstr(p)?;
-    cvt(unsafe { libc::unlink(p.as_ptr()) })?;
-    Ok(())
-}
-
-pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
-    let old = cstr(old)?;
-    let new = cstr(new)?;
-    cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?;
-    Ok(())
-}
-
-pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
-    let p = cstr(p)?;
-    cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?;
-    Ok(())
-}
-
-pub fn rmdir(p: &Path) -> io::Result<()> {
-    let p = cstr(p)?;
-    cvt(unsafe { libc::rmdir(p.as_ptr()) })?;
-    Ok(())
-}
-
-pub fn remove_dir_all(path: &Path) -> io::Result<()> {
-    let filetype = lstat(path)?.file_type();
-    if filetype.is_symlink() { unlink(path) } else { remove_dir_all_recursive(path) }
-}
-
-fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
-    for child in readdir(path)? {
-        let child = child?;
-        if child.file_type()?.is_dir() {
-            remove_dir_all_recursive(&child.path())?;
-        } else {
-            unlink(&child.path())?;
-        }
-    }
-    rmdir(path)
-}
-
-pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let c_path = cstr(p)?;
-    let p = c_path.as_ptr();
-
-    let mut buf = Vec::with_capacity(256);
-
-    loop {
-        let buf_read =
-            cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize;
-
-        unsafe {
-            buf.set_len(buf_read);
-        }
-
-        if buf_read != buf.capacity() {
-            buf.shrink_to_fit();
-
-            return Ok(PathBuf::from(OsString::from_vec(buf)));
-        }
-
-        // Trigger the internal buffer resizing logic of `Vec` by requiring
-        // more space than the current capacity. The length is guaranteed to be
-        // the same as the capacity due to the if statement above.
-        buf.reserve(1);
-    }
-}
-
-pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
-    let src = cstr(src)?;
-    let dst = cstr(dst)?;
-    cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?;
-    Ok(())
-}
-
-pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
-    let src = cstr(src)?;
-    let dst = cstr(dst)?;
-    cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
-    Ok(())
-}
-
-pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let p = cstr(p)?;
-    let mut stat: stat64 = unsafe { mem::zeroed() };
-    cvt(unsafe { libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?;
-    Ok(FileAttr { stat })
-}
-
-pub fn lstat(p: &Path) -> io::Result<FileAttr> {
-    let p = cstr(p)?;
-    let mut stat: stat64 = unsafe { mem::zeroed() };
-    cvt(unsafe { ::libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?;
-    Ok(FileAttr { stat })
-}
-
-pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
-    use crate::sys::vxworks::ext::ffi::OsStrExt;
-    let path = CString::new(p.as_os_str().as_bytes())?;
-    let buf;
-    unsafe {
-        let r = libc::realpath(path.as_ptr(), ptr::null_mut());
-        if r.is_null() {
-            return Err(io::Error::last_os_error());
-        }
-        buf = CStr::from_ptr(r).to_bytes().to_vec();
-        libc::free(r as *mut _);
-    }
-    Ok(PathBuf::from(OsString::from_vec(buf)))
-}
-
-pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
-    use crate::fs::File;
-    if !from.is_file() {
-        return Err(Error::new(
-            ErrorKind::InvalidInput,
-            "the source path is not an existing regular file",
-        ));
-    }
-
-    let mut reader = File::open(from)?;
-    let mut writer = File::create(to)?;
-    let perm = reader.metadata()?.permissions();
-
-    let ret = io::copy(&mut reader, &mut writer)?;
-    writer.set_permissions(perm)?;
-    Ok(ret)
-}
diff --git a/library/std/src/sys/vxworks/io.rs b/library/std/src/sys/vxworks/io.rs
deleted file mode 100644
index 0f68ebf..0000000
--- a/library/std/src/sys/vxworks/io.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use crate::marker::PhantomData;
-use crate::slice;
-
-use libc::{c_void, iovec};
-
-#[derive(Copy, Clone)]
-#[repr(transparent)]
-pub struct IoSlice<'a> {
-    vec: iovec,
-    _p: PhantomData<&'a [u8]>,
-}
-
-impl<'a> IoSlice<'a> {
-    #[inline]
-    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
-        IoSlice {
-            vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() },
-            _p: PhantomData,
-        }
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        if self.vec.iov_len < n {
-            panic!("advancing IoSlice beyond its length");
-        }
-
-        unsafe {
-            self.vec.iov_len -= n;
-            self.vec.iov_base = self.vec.iov_base.add(n);
-        }
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
-    }
-}
-
-pub struct IoSliceMut<'a> {
-    vec: iovec,
-    _p: PhantomData<&'a mut [u8]>,
-}
-
-impl<'a> IoSliceMut<'a> {
-    #[inline]
-    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
-        IoSliceMut {
-            vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() },
-            _p: PhantomData,
-        }
-    }
-
-    #[inline]
-    pub fn advance(&mut self, n: usize) {
-        if self.vec.iov_len < n {
-            panic!("advancing IoSliceMut beyond its length");
-        }
-
-        unsafe {
-            self.vec.iov_len -= n;
-            self.vec.iov_base = self.vec.iov_base.add(n);
-        }
-    }
-
-    #[inline]
-    pub fn as_slice(&self) -> &[u8] {
-        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
-    }
-
-    #[inline]
-    pub fn as_mut_slice(&mut self) -> &mut [u8] {
-        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
-    }
-}
diff --git a/library/std/src/sys/vxworks/memchr.rs b/library/std/src/sys/vxworks/memchr.rs
deleted file mode 100644
index 928100c..0000000
--- a/library/std/src/sys/vxworks/memchr.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Original implementation taken from rust-memchr.
-// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
-
-pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
-    let p = unsafe {
-        libc::memchr(
-            haystack.as_ptr() as *const libc::c_void,
-            needle as libc::c_int,
-            haystack.len(),
-        )
-    };
-    if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
-}
-
-pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
-    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
-        core::slice::memchr::memrchr(needle, haystack)
-    }
-
-    memrchr_specific(needle, haystack)
-}
diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs
index 1132a84..c20edaa 100644
--- a/library/std/src/sys/vxworks/mod.rs
+++ b/library/std/src/sys/vxworks/mod.rs
@@ -7,29 +7,53 @@
 pub use crate::os::vxworks as platform;
 pub use libc::strlen;
 
+#[macro_use]
+#[path = "../unix/weak.rs"]
+pub mod weak;
+
+#[path = "../unix/alloc.rs"]
 pub mod alloc;
+#[path = "../unix/args.rs"]
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
+#[path = "../unix/condvar.rs"]
 pub mod condvar;
 pub mod env;
+#[path = "../unix/ext/mod.rs"]
 pub mod ext;
+#[path = "../unix/fd.rs"]
 pub mod fd;
+#[path = "../unix/fs.rs"]
 pub mod fs;
+#[path = "../unix/io.rs"]
 pub mod io;
+#[path = "../unix/memchr.rs"]
 pub mod memchr;
+#[path = "../unix/mutex.rs"]
 pub mod mutex;
+#[path = "../unix/net.rs"]
 pub mod net;
+#[path = "../unix/os.rs"]
 pub mod os;
+#[path = "../unix/path.rs"]
 pub mod path;
+#[path = "../unix/pipe.rs"]
 pub mod pipe;
 pub mod process;
 pub mod rand;
+#[path = "../unix/rwlock.rs"]
 pub mod rwlock;
+#[path = "../unix/stack_overflow.rs"]
 pub mod stack_overflow;
+#[path = "../unix/stdio.rs"]
 pub mod stdio;
+#[path = "../unix/thread.rs"]
 pub mod thread;
 pub mod thread_local_dtor;
+#[path = "../unix/thread_local_key.rs"]
 pub mod thread_local_key;
+#[path = "../unix/time.rs"]
 pub mod time;
 
 pub use crate::sys_common::os_str_bytes as os_str;
diff --git a/library/std/src/sys/vxworks/mutex.rs b/library/std/src/sys/vxworks/mutex.rs
deleted file mode 100644
index 103d87e..0000000
--- a/library/std/src/sys/vxworks/mutex.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
-
-pub struct Mutex {
-    inner: UnsafeCell<libc::pthread_mutex_t>,
-}
-
-#[inline]
-pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
-    m.inner.get()
-}
-
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {}
-
-#[allow(dead_code)] // sys isn't exported yet
-impl Mutex {
-    pub const fn new() -> Mutex {
-        // Might be moved to a different address, so it is better to avoid
-        // initialization of potentially opaque OS data before it landed.
-        // Be very careful using this newly constructed `Mutex`, reentrant
-        // locking is undefined behavior until `init` is called!
-        Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
-    }
-    #[inline]
-    pub unsafe fn init(&mut self) {
-        // Issue #33770
-        //
-        // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
-        // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you
-        // try to re-lock it from the same thread when you already hold a lock.
-        //
-        // In practice, glibc takes advantage of this undefined behavior to
-        // implement hardware lock elision, which uses hardware transactional
-        // memory to avoid acquiring the lock. While a transaction is in
-        // progress, the lock appears to be unlocked. This isn't a problem for
-        // other threads since the transactional memory will abort if a conflict
-        // is detected, however no abort is generated if re-locking from the
-        // same thread.
-        //
-        // Since locking the same mutex twice will result in two aliasing &mut
-        // references, we instead create the mutex with type
-        // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
-        // re-lock it from the same thread, thus avoiding undefined behavior.
-        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
-        let r = libc::pthread_mutexattr_init(attr.as_mut_ptr());
-        debug_assert_eq!(r, 0);
-        let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL);
-        debug_assert_eq!(r, 0);
-        let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr());
-        debug_assert_eq!(r, 0);
-        let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
-        debug_assert_eq!(r, 0);
-    }
-    #[inline]
-    pub unsafe fn lock(&self) {
-        let r = libc::pthread_mutex_lock(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        let r = libc::pthread_mutex_unlock(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        libc::pthread_mutex_trylock(self.inner.get()) == 0
-    }
-    #[inline]
-    #[cfg(not(target_os = "dragonfly"))]
-    pub unsafe fn destroy(&self) {
-        let r = libc::pthread_mutex_destroy(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-    #[inline]
-    #[cfg(target_os = "dragonfly")]
-    pub unsafe fn destroy(&self) {
-        let r = libc::pthread_mutex_destroy(self.inner.get());
-        // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
-        // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
-        // Once it is used (locked/unlocked) or pthread_mutex_init() is called,
-        // this behaviour no longer occurs.
-        debug_assert!(r == 0 || r == libc::EINVAL);
-    }
-}
-
-pub struct ReentrantMutex {
-    inner: UnsafeCell<libc::pthread_mutex_t>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
-    pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
-    }
-
-    pub unsafe fn init(&self) {
-        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
-        let result = libc::pthread_mutexattr_init(attr.as_mut_ptr());
-        debug_assert_eq!(result, 0);
-        let result =
-            libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE);
-        debug_assert_eq!(result, 0);
-        let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr());
-        debug_assert_eq!(result, 0);
-        let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
-        debug_assert_eq!(result, 0);
-    }
-
-    pub unsafe fn lock(&self) {
-        let result = libc::pthread_mutex_lock(self.inner.get());
-        debug_assert_eq!(result, 0);
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        libc::pthread_mutex_trylock(self.inner.get()) == 0
-    }
-
-    pub unsafe fn unlock(&self) {
-        let result = libc::pthread_mutex_unlock(self.inner.get());
-        debug_assert_eq!(result, 0);
-    }
-
-    pub unsafe fn destroy(&self) {
-        let result = libc::pthread_mutex_destroy(self.inner.get());
-        debug_assert_eq!(result, 0);
-    }
-}
diff --git a/library/std/src/sys/vxworks/net.rs b/library/std/src/sys/vxworks/net.rs
deleted file mode 100644
index 7613fbe..0000000
--- a/library/std/src/sys/vxworks/net.rs
+++ /dev/null
@@ -1,335 +0,0 @@
-#[cfg(all(test, taget_env = "gnu"))]
-mod tests;
-
-use crate::cmp;
-use crate::ffi::CStr;
-use crate::io;
-use crate::io::{IoSlice, IoSliceMut};
-use crate::mem;
-use crate::net::{Shutdown, SocketAddr};
-use crate::str;
-use crate::sys::fd::FileDesc;
-use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-use crate::time::{Duration, Instant};
-use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK};
-
-pub use crate::sys::{cvt, cvt_r};
-
-#[allow(unused_extern_crates)]
-pub extern crate libc as netc;
-
-pub type wrlen_t = size_t;
-
-pub struct Socket(FileDesc);
-
-pub fn init() {}
-
-pub fn cvt_gai(err: c_int) -> io::Result<()> {
-    if err == 0 {
-        return Ok(());
-    }
-
-    // We may need to trigger a glibc workaround. See on_resolver_failure() for details.
-    on_resolver_failure();
-
-    if err == EAI_SYSTEM {
-        return Err(io::Error::last_os_error());
-    }
-
-    let detail = unsafe {
-        str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
-    };
-    Err(io::Error::new(
-        io::ErrorKind::Other,
-        &format!("failed to lookup address information: {}", detail)[..],
-    ))
-}
-
-impl Socket {
-    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
-        let fam = match *addr {
-            SocketAddr::V4(..) => libc::AF_INET,
-            SocketAddr::V6(..) => libc::AF_INET6,
-        };
-        Socket::new_raw(fam, ty)
-    }
-
-    pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
-        unsafe {
-            let fd = cvt(libc::socket(fam, ty, 0))?;
-            let fd = FileDesc::new(fd);
-            fd.set_cloexec()?;
-            let socket = Socket(fd);
-            Ok(socket)
-        }
-    }
-
-    pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> {
-        unimplemented!();
-    }
-
-    pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
-        self.set_nonblocking(true)?;
-        let r = unsafe {
-            let (addrp, len) = addr.into_inner();
-            cvt(libc::connect(self.0.raw(), addrp, len))
-        };
-        self.set_nonblocking(false)?;
-
-        match r {
-            Ok(_) => return Ok(()),
-            // there's no ErrorKind for EINPROGRESS :(
-            Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
-            Err(e) => return Err(e),
-        }
-
-        let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 };
-
-        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::Error::new(
-                io::ErrorKind::InvalidInput,
-                "cannot set a 0 duration timeout",
-            ));
-        }
-
-        let start = Instant::now();
-
-        loop {
-            let elapsed = start.elapsed();
-            if elapsed >= timeout {
-                return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out"));
-            }
-
-            let timeout = timeout - elapsed;
-            let mut timeout = timeout
-                .as_secs()
-                .saturating_mul(1_000)
-                .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
-            if timeout == 0 {
-                timeout = 1;
-            }
-
-            let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
-
-            match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
-                -1 => {
-                    let err = io::Error::last_os_error();
-                    if err.kind() != io::ErrorKind::Interrupted {
-                        return Err(err);
-                    }
-                }
-                0 => {}
-                _ => {
-                    // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
-                    // for POLLHUP rather than read readiness
-                    if pollfd.revents & libc::POLLHUP != 0 {
-                        let e = self.take_error()?.unwrap_or_else(|| {
-                            io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
-                        });
-                        return Err(e);
-                    }
-
-                    return Ok(());
-                }
-            }
-        }
-    }
-
-    pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
-        let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
-        let fd = FileDesc::new(fd);
-        fd.set_cloexec()?;
-        Ok(Socket(fd))
-    }
-
-    pub fn duplicate(&self) -> io::Result<Socket> {
-        self.0.duplicate().map(Socket)
-    }
-
-    fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
-        let ret = cvt(unsafe {
-            libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
-        })?;
-        Ok(ret as usize)
-    }
-
-    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.recv_with_flags(buf, 0)
-    }
-
-    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.recv_with_flags(buf, MSG_PEEK)
-    }
-
-    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        self.0.read_vectored(bufs)
-    }
-
-    #[inline]
-    pub fn is_read_vectored(&self) -> bool {
-        self.0.is_read_vectored()
-    }
-
-    fn recv_from_with_flags(
-        &self,
-        buf: &mut [u8],
-        flags: c_int,
-    ) -> io::Result<(usize, SocketAddr)> {
-        let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
-        let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t;
-
-        let n = cvt(unsafe {
-            libc::recvfrom(
-                self.0.raw(),
-                buf.as_mut_ptr() as *mut c_void,
-                buf.len(),
-                flags,
-                &mut storage as *mut _ as *mut _,
-                &mut addrlen,
-            )
-        })?;
-        Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
-    }
-
-    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        self.recv_from_with_flags(buf, 0)
-    }
-
-    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        self.recv_from_with_flags(buf, MSG_PEEK)
-    }
-
-    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
-    }
-
-    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        self.0.write_vectored(bufs)
-    }
-
-    #[inline]
-    pub fn is_write_vectored(&self) -> bool {
-        self.0.is_write_vectored()
-    }
-
-    pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
-        let timeout = match dur {
-            Some(dur) => {
-                if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
-                    return Err(io::Error::new(
-                        io::ErrorKind::InvalidInput,
-                        "cannot set a 0 duration timeout",
-                    ));
-                }
-
-                let secs = if dur.as_secs() > libc::time_t::MAX as u64 {
-                    libc::time_t::MAX
-                } else {
-                    dur.as_secs() as libc::time_t
-                };
-                let mut timeout = libc::timeval {
-                    tv_sec: secs,
-                    tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t,
-                };
-                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
-                    timeout.tv_usec = 1;
-                }
-                timeout
-            }
-            None => libc::timeval { tv_sec: 0, tv_usec: 0 },
-        };
-        setsockopt(self, libc::SOL_SOCKET, kind, timeout)
-    }
-
-    pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
-        let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?;
-        if raw.tv_sec == 0 && raw.tv_usec == 0 {
-            Ok(None)
-        } else {
-            let sec = raw.tv_sec as u64;
-            let nsec = (raw.tv_usec as u32) * 1000;
-            Ok(Some(Duration::new(sec, nsec)))
-        }
-    }
-
-    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
-        let how = match how {
-            Shutdown::Write => libc::SHUT_WR,
-            Shutdown::Read => libc::SHUT_RD,
-            Shutdown::Both => libc::SHUT_RDWR,
-        };
-        cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
-        Ok(())
-    }
-
-    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
-        setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
-    }
-
-    pub fn nodelay(&self) -> io::Result<bool> {
-        let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?;
-        Ok(raw != 0)
-    }
-
-    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
-        let mut nonblocking = nonblocking as libc::c_int;
-        cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop)
-    }
-
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
-        if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
-    }
-}
-
-impl AsInner<c_int> for Socket {
-    fn as_inner(&self) -> &c_int {
-        self.0.as_inner()
-    }
-}
-
-impl FromInner<c_int> for Socket {
-    fn from_inner(fd: c_int) -> Socket {
-        Socket(FileDesc::new(fd))
-    }
-}
-
-impl IntoInner<c_int> for Socket {
-    fn into_inner(self) -> c_int {
-        self.0.into_raw()
-    }
-}
-
-// In versions of glibc prior to 2.26, there's a bug where the DNS resolver
-// will cache the contents of /etc/resolv.conf, so changes to that file on disk
-// can be ignored by a long-running program. That can break DNS lookups on e.g.
-// laptops where the network comes and goes. See
-// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some
-// distros including Debian have patched glibc to fix this for a long time.
-//
-// A workaround for this bug is to call the res_init libc function, to clear
-// the cached configs. Unfortunately, while we believe glibc's implementation
-// of res_init is thread-safe, we know that other implementations are not
-// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
-// try to synchronize its res_init calls with a Mutex, but that wouldn't
-// protect programs that call into libc in other ways. So instead of calling
-// res_init unconditionally, we call it only when we detect we're linking
-// against glibc version < 2.26. (That is, when we both know its needed and
-// believe it's thread-safe).
-#[cfg(target_env = "gnu")]
-fn on_resolver_failure() {
-    /*
-    use crate::sys;
-
-    // If the version fails to parse, we treat it the same as "not glibc".
-    if let Some(version) = sys::os::glibc_version() {
-        if version < (2, 26) {
-            unsafe { libc::res_init() };
-        }
-    }
-    */
-}
-
-#[cfg(not(target_env = "gnu"))]
-fn on_resolver_failure() {}
diff --git a/library/std/src/sys/vxworks/net/tests.rs b/library/std/src/sys/vxworks/net/tests.rs
deleted file mode 100644
index e7c6e34..0000000
--- a/library/std/src/sys/vxworks/net/tests.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use super::*;
-
-#[test]
-fn test_res_init() {
-    // This mostly just tests that the weak linkage doesn't panic wildly...
-    res_init_if_glibc_before_2_26().unwrap();
-}
-
-#[test]
-fn test_parse_glibc_version() {
-    let cases = [
-        ("0.0", Some((0, 0))),
-        ("01.+2", Some((1, 2))),
-        ("3.4.5.six", Some((3, 4))),
-        ("1", None),
-        ("1.-2", None),
-        ("1.foo", None),
-        ("foo.1", None),
-    ];
-    for &(version_str, parsed) in cases.iter() {
-        assert_eq!(parsed, parse_glibc_version(version_str));
-    }
-}
diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs
deleted file mode 100644
index 1fadf71..0000000
--- a/library/std/src/sys/vxworks/os.rs
+++ /dev/null
@@ -1,316 +0,0 @@
-use crate::error::Error as StdError;
-use crate::ffi::{CStr, CString, OsStr, OsString};
-use crate::fmt;
-use crate::io;
-use crate::iter;
-use crate::marker::PhantomData;
-use crate::mem;
-use crate::memchr;
-use crate::path::{self, Path, PathBuf};
-use crate::slice;
-use crate::str;
-use crate::sys::cvt;
-use crate::sys_common::mutex::{Mutex, MutexGuard};
-use libc::{self, c_char /*,c_void */, c_int};
-/*use sys::fd; this one is probably important */
-use crate::vec;
-
-const TMPBUF_SZ: usize = 128;
-
-// This is a terrible fix
-use crate::sys::os_str::Buf;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-
-pub trait OsStringExt {
-    fn from_vec(vec: Vec<u8>) -> Self;
-    fn into_vec(self) -> Vec<u8>;
-}
-
-impl OsStringExt for OsString {
-    fn from_vec(vec: Vec<u8>) -> OsString {
-        FromInner::from_inner(Buf { inner: vec })
-    }
-    fn into_vec(self) -> Vec<u8> {
-        self.into_inner().inner
-    }
-}
-
-pub trait OsStrExt {
-    fn from_bytes(slice: &[u8]) -> &Self;
-    fn as_bytes(&self) -> &[u8];
-}
-
-impl OsStrExt for OsStr {
-    fn from_bytes(slice: &[u8]) -> &OsStr {
-        unsafe { mem::transmute(slice) }
-    }
-    fn as_bytes(&self) -> &[u8] {
-        &self.as_inner().inner
-    }
-}
-
-pub fn errno() -> i32 {
-    unsafe { libc::errnoGet() }
-}
-
-pub fn set_errno(e: i32) {
-    unsafe {
-        libc::errnoSet(e as c_int);
-    }
-}
-
-/// Gets a detailed string description for the given error number.
-pub fn error_string(errno: i32) -> String {
-    let mut buf = [0 as c_char; TMPBUF_SZ];
-    extern "C" {
-        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
-    }
-
-    let p = buf.as_mut_ptr();
-    unsafe {
-        if strerror_r(errno as c_int, p, buf.len()) < 0 {
-            panic!("strerror_r failure");
-        }
-        let p = p as *const _;
-        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
-    }
-}
-
-pub fn getcwd() -> io::Result<PathBuf> {
-    let mut buf = Vec::with_capacity(512);
-    loop {
-        unsafe {
-            let ptr = buf.as_mut_ptr() as *mut libc::c_char;
-            if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() {
-                let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
-                buf.set_len(len);
-                buf.shrink_to_fit();
-                return Ok(PathBuf::from(OsString::from_vec(buf)));
-            } else {
-                let error = io::Error::last_os_error();
-                if error.raw_os_error() != Some(libc::ERANGE) {
-                    return Err(error);
-                }
-            }
-            // Trigger the internal buffer resizing logic of `Vec` by requiring
-            // more space than the current capacity.
-            let cap = buf.capacity();
-            buf.set_len(cap);
-            buf.reserve(1);
-        }
-    }
-}
-
-pub fn chdir(p: &path::Path) -> io::Result<()> {
-    let p: &OsStr = p.as_ref();
-    let p = CString::new(p.as_bytes())?;
-    unsafe {
-        match libc::chdir(p.as_ptr()) == (0 as c_int) {
-            true => Ok(()),
-            false => Err(io::Error::last_os_error()),
-        }
-    }
-}
-
-pub struct SplitPaths<'a> {
-    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>,
-}
-
-pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
-    fn bytes_to_path(b: &[u8]) -> PathBuf {
-        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
-    }
-    fn is_colon(b: &u8) -> bool {
-        *b == b':'
-    }
-    let unparsed = unparsed.as_bytes();
-    SplitPaths {
-        iter: unparsed
-            .split(is_colon as fn(&u8) -> bool)
-            .map(bytes_to_path as fn(&[u8]) -> PathBuf),
-    }
-}
-
-impl<'a> Iterator for SplitPaths<'a> {
-    type Item = PathBuf;
-    fn next(&mut self) -> Option<PathBuf> {
-        self.iter.next()
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-#[derive(Debug)]
-pub struct JoinPathsError;
-
-pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
-where
-    I: Iterator<Item = T>,
-    T: AsRef<OsStr>,
-{
-    let mut joined = Vec::new();
-    let sep = b':';
-
-    for (i, path) in paths.enumerate() {
-        let path = path.as_ref().as_bytes();
-        if i > 0 {
-            joined.push(sep)
-        }
-        if path.contains(&sep) {
-            return Err(JoinPathsError);
-        }
-        joined.extend_from_slice(path);
-    }
-    Ok(OsStringExt::from_vec(joined))
-}
-
-impl fmt::Display for JoinPathsError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        "path segment contains separator `:`".fmt(f)
-    }
-}
-
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "failed to join paths"
-    }
-}
-
-pub fn current_exe() -> io::Result<PathBuf> {
-    #[cfg(test)]
-    use realstd::env;
-
-    #[cfg(not(test))]
-    use crate::env;
-
-    let exe_path = env::args().next().unwrap();
-    let path = Path::new(&exe_path);
-    path.canonicalize()
-}
-
-pub struct Env {
-    iter: vec::IntoIter<(OsString, OsString)>,
-    _dont_send_or_sync_me: PhantomData<*mut ()>,
-}
-
-impl Iterator for Env {
-    type Item = (OsString, OsString);
-    fn next(&mut self) -> Option<(OsString, OsString)> {
-        self.iter.next()
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-pub unsafe fn environ() -> *mut *const *const c_char {
-    extern "C" {
-        static mut environ: *const *const c_char;
-    }
-    &mut environ
-}
-
-pub unsafe fn env_lock() -> MutexGuard<'static> {
-    // We never call `ENV_LOCK.init()`, so it is UB to attempt to
-    // acquire this mutex reentrantly!
-    static ENV_LOCK: Mutex = Mutex::new();
-    ENV_LOCK.lock()
-}
-
-/// Returns a vector of (variable, value) byte-vector pairs for all the
-/// environment variables of the current process.
-pub fn env() -> Env {
-    unsafe {
-        let _guard = env_lock();
-        let mut environ = *environ();
-        if environ.is_null() {
-            panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error());
-        }
-        let mut result = Vec::new();
-        while !(*environ).is_null() {
-            if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
-                result.push(key_value);
-            }
-            environ = environ.add(1);
-        }
-        return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData };
-    }
-
-    fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
-        // Strategy (copied from glibc): Variable name and value are separated
-        // by an ASCII equals sign '='. Since a variable name must not be
-        // empty, allow variable names starting with an equals sign. Skip all
-        // malformed lines.
-        if input.is_empty() {
-            return None;
-        }
-        let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
-        pos.map(|p| {
-            (
-                OsStringExt::from_vec(input[..p].to_vec()),
-                OsStringExt::from_vec(input[p + 1..].to_vec()),
-            )
-        })
-    }
-}
-
-pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
-    // environment variables with a nul byte can't be set, so their value is
-    // always None as well
-    let k = CString::new(k.as_bytes())?;
-    unsafe {
-        let _guard = env_lock();
-        let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
-        let ret = if s.is_null() {
-            None
-        } else {
-            Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
-        };
-        Ok(ret)
-    }
-}
-
-pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
-    let k = CString::new(k.as_bytes())?;
-    let v = CString::new(v.as_bytes())?;
-
-    unsafe {
-        let _guard = env_lock();
-        cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
-    }
-}
-
-pub fn unsetenv(n: &OsStr) -> io::Result<()> {
-    let nbuf = CString::new(n.as_bytes())?;
-
-    unsafe {
-        let _guard = env_lock();
-        cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
-    }
-}
-
-pub fn page_size() -> usize {
-    unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
-}
-
-pub fn temp_dir() -> PathBuf {
-    crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/tmp"))
-}
-
-pub fn home_dir() -> Option<PathBuf> {
-    crate::env::var_os("HOME").or_else(|| None).map(PathBuf::from)
-}
-
-pub fn exit(code: i32) -> ! {
-    unsafe { libc::exit(code as c_int) }
-}
-
-pub fn getpid() -> u32 {
-    unsafe { libc::getpid() as u32 }
-}
-
-pub fn getppid() -> u32 {
-    unsafe { libc::getppid() as u32 }
-}
diff --git a/library/std/src/sys/vxworks/path.rs b/library/std/src/sys/vxworks/path.rs
deleted file mode 100644
index 840a7ae..0000000
--- a/library/std/src/sys/vxworks/path.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use crate::ffi::OsStr;
-use crate::path::Prefix;
-
-#[inline]
-pub fn is_sep_byte(b: u8) -> bool {
-    b == b'/'
-}
-
-#[inline]
-pub fn is_verbatim_sep(b: u8) -> bool {
-    b == b'/'
-}
-
-pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
-    None
-}
-
-pub const MAIN_SEP_STR: &str = "/";
-pub const MAIN_SEP: char = '/';
diff --git a/library/std/src/sys/vxworks/pipe.rs b/library/std/src/sys/vxworks/pipe.rs
deleted file mode 100644
index a183762..0000000
--- a/library/std/src/sys/vxworks/pipe.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::mem;
-use crate::sync::atomic::AtomicBool;
-use crate::sys::fd::FileDesc;
-use crate::sys::{cvt, cvt_r};
-use libc::{self /*, c_int apparently not used? */};
-
-pub struct AnonPipe(FileDesc);
-
-pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
-    static INVALID: AtomicBool = AtomicBool::new(false);
-
-    let mut fds = [0; 2];
-    cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
-
-    let fd0 = FileDesc::new(fds[0]);
-    let fd1 = FileDesc::new(fds[1]);
-    fd0.set_cloexec()?;
-    fd1.set_cloexec()?;
-    Ok((AnonPipe(fd0), AnonPipe(fd1)))
-}
-
-impl AnonPipe {
-    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.0.read(buf)
-    }
-
-    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        self.0.read_vectored(bufs)
-    }
-
-    #[inline]
-    pub fn is_read_vectored(&self) -> bool {
-        self.0.is_read_vectored()
-    }
-
-    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
-    }
-
-    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        self.0.write_vectored(bufs)
-    }
-
-    #[inline]
-    pub fn is_write_vectored(&self) -> bool {
-        self.0.is_write_vectored()
-    }
-
-    pub fn fd(&self) -> &FileDesc {
-        &self.0
-    }
-    pub fn into_fd(self) -> FileDesc {
-        self.0
-    }
-    pub fn diverge(&self) -> ! {
-        panic!()
-    }
-}
-
-pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> {
-    // Set both pipes into nonblocking mode as we're gonna be reading from both
-    // in the `select` loop below, and we wouldn't want one to block the other!
-    let p1 = p1.into_fd();
-    let p2 = p2.into_fd();
-    p1.set_nonblocking_pipe(true)?;
-    p2.set_nonblocking_pipe(true)?;
-
-    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
-    fds[0].fd = p1.raw();
-    fds[0].events = libc::POLLIN;
-    fds[1].fd = p2.raw();
-    fds[1].events = libc::POLLIN;
-    loop {
-        // wait for either pipe to become readable using `poll`
-        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
-
-        if fds[0].revents != 0 && read(&p1, v1)? {
-            p2.set_nonblocking_pipe(false)?;
-            return p2.read_to_end(v2).map(drop);
-        }
-        if fds[1].revents != 0 && read(&p2, v2)? {
-            p1.set_nonblocking_pipe(false)?;
-            return p1.read_to_end(v1).map(drop);
-        }
-    }
-
-    // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
-    // EAGAIN. If we hit EOF, then this will happen because the underlying
-    // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
-    // this case we flip the other fd back into blocking mode and read
-    // whatever's leftover on that file descriptor.
-    fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> {
-        match fd.read_to_end(dst) {
-            Ok(_) => Ok(true),
-            Err(e) => {
-                if e.raw_os_error() == Some(libc::EWOULDBLOCK)
-                    || e.raw_os_error() == Some(libc::EAGAIN)
-                {
-                    Ok(false)
-                } else {
-                    Err(e)
-                }
-            }
-        }
-    }
-}
diff --git a/library/std/src/sys/vxworks/process/mod.rs b/library/std/src/sys/vxworks/process/mod.rs
index c59782f..dc6130e 100644
--- a/library/std/src/sys/vxworks/process/mod.rs
+++ b/library/std/src/sys/vxworks/process/mod.rs
@@ -1,7 +1,9 @@
-pub use self::process_common::{Command, ExitCode, ExitStatus, Stdio, StdioPipes};
-pub use self::process_inner::Process;
+pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
+pub use self::process_inner::{ExitStatus, Process};
 pub use crate::ffi::OsString as EnvKey;
+pub use crate::sys_common::process::CommandEnvs;
 
+#[path = "../../unix/process/process_common.rs"]
 mod process_common;
 #[path = "process_vxworks.rs"]
 mod process_inner;
diff --git a/library/std/src/sys/vxworks/process/process_common.rs b/library/std/src/sys/vxworks/process/process_common.rs
deleted file mode 100644
index 6473a0c..0000000
--- a/library/std/src/sys/vxworks/process/process_common.rs
+++ /dev/null
@@ -1,399 +0,0 @@
-use crate::os::unix::prelude::*;
-
-use crate::collections::BTreeMap;
-use crate::ffi::{CStr, CString, OsStr, OsString};
-use crate::fmt;
-use crate::io;
-use crate::ptr;
-use crate::sys::fd::FileDesc;
-use crate::sys::fs::{File, OpenOptions};
-use crate::sys::pipe::{self, AnonPipe};
-use crate::sys_common::process::CommandEnv;
-
-use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS};
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
-    // Currently we try hard to ensure that the call to `.exec()` doesn't
-    // actually allocate any memory. While many platforms try to ensure that
-    // memory allocation works after a fork in a multithreaded process, it's
-    // been observed to be buggy and somewhat unreliable, so we do our best to
-    // just not do it at all!
-    //
-    // Along those lines, the `argv` and `envp` raw pointers here are exactly
-    // what's gonna get passed to `execvp`. The `argv` array starts with the
-    // `program` and ends with a NULL, and the `envp` pointer, if present, is
-    // also null-terminated.
-    //
-    // Right now we don't support removing arguments, so there's no much fancy
-    // support there, but we support adding and removing environment variables,
-    // so a side table is used to track where in the `envp` array each key is
-    // located. Whenever we add a key we update it in place if it's already
-    // present, and whenever we remove a key we update the locations of all
-    // other keys.
-    program: CString,
-    args: Vec<CString>,
-    argv: Argv,
-    env: CommandEnv,
-
-    cwd: Option<CString>,
-    uid: Option<uid_t>,
-    gid: Option<gid_t>,
-    saw_nul: bool,
-    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
-    stdin: Option<Stdio>,
-    stdout: Option<Stdio>,
-    stderr: Option<Stdio>,
-}
-
-// Create a new type for `Argv`, so that we can make it `Send` and `Sync`
-struct Argv(Vec<*const c_char>);
-
-// It is safe to make `Argv` `Send` and `Sync`, because it contains
-// pointers to memory owned by `Command.args`
-unsafe impl Send for Argv {}
-unsafe impl Sync for Argv {}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
-    pub stdin: Option<AnonPipe>,
-    pub stdout: Option<AnonPipe>,
-    pub stderr: Option<AnonPipe>,
-}
-
-// passed to do_exec() with configuration of what the child stdio should look
-// like
-pub struct ChildPipes {
-    pub stdin: ChildStdio,
-    pub stdout: ChildStdio,
-    pub stderr: ChildStdio,
-}
-
-pub enum ChildStdio {
-    Inherit,
-    Explicit(c_int),
-    Owned(FileDesc),
-}
-
-pub enum Stdio {
-    Inherit,
-    Null,
-    MakePipe,
-    Fd(FileDesc),
-}
-
-impl Command {
-    pub fn new(program: &OsStr) -> Command {
-        let mut saw_nul = false;
-        let program = os2c(program, &mut saw_nul);
-        Command {
-            argv: Argv(vec![program.as_ptr(), ptr::null()]),
-            args: vec![program.clone()],
-            program,
-            env: Default::default(),
-            cwd: None,
-            uid: None,
-            gid: None,
-            saw_nul,
-            closures: Vec::new(),
-            stdin: None,
-            stdout: None,
-            stderr: None,
-        }
-    }
-
-    pub fn set_arg_0(&mut self, arg: &OsStr) {
-        // Set a new arg0
-        let arg = os2c(arg, &mut self.saw_nul);
-        debug_assert!(self.argv.0.len() > 1);
-        self.argv.0[0] = arg.as_ptr();
-        self.args[0] = arg;
-    }
-
-    pub fn arg(&mut self, arg: &OsStr) {
-        // Overwrite the trailing NULL pointer in `argv` and then add a new null
-        // pointer.
-        let arg = os2c(arg, &mut self.saw_nul);
-        self.argv.0[self.args.len()] = arg.as_ptr();
-        self.argv.0.push(ptr::null());
-
-        // Also make sure we keep track of the owned value to schedule a
-        // destructor for this memory.
-        self.args.push(arg);
-    }
-
-    pub fn cwd(&mut self, dir: &OsStr) {
-        self.cwd = Some(os2c(dir, &mut self.saw_nul));
-    }
-    pub fn uid(&mut self, id: uid_t) {
-        self.uid = Some(id);
-    }
-    pub fn gid(&mut self, id: gid_t) {
-        self.gid = Some(id);
-    }
-
-    pub fn saw_nul(&self) -> bool {
-        self.saw_nul
-    }
-    pub fn get_argv(&self) -> &Vec<*const c_char> {
-        &self.argv.0
-    }
-
-    pub fn get_program(&self) -> &CStr {
-        &*self.program
-    }
-
-    #[allow(dead_code)]
-    pub fn get_cwd(&self) -> &Option<CString> {
-        &self.cwd
-    }
-    #[allow(dead_code)]
-    pub fn get_uid(&self) -> Option<uid_t> {
-        self.uid
-    }
-    #[allow(dead_code)]
-    pub fn get_gid(&self) -> Option<gid_t> {
-        self.gid
-    }
-
-    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
-        &mut self.closures
-    }
-
-    pub unsafe fn pre_exec(&mut self, _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
-        // Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
-        unimplemented!();
-    }
-
-    pub fn stdin(&mut self, stdin: Stdio) {
-        self.stdin = Some(stdin);
-    }
-
-    pub fn stdout(&mut self, stdout: Stdio) {
-        self.stdout = Some(stdout);
-    }
-
-    pub fn stderr(&mut self, stderr: Stdio) {
-        self.stderr = Some(stderr);
-    }
-
-    pub fn env_mut(&mut self) -> &mut CommandEnv {
-        &mut self.env
-    }
-
-    pub fn capture_env(&mut self) -> Option<CStringArray> {
-        let maybe_env = self.env.capture_if_changed();
-        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
-    }
-    #[allow(dead_code)]
-    pub fn env_saw_path(&self) -> bool {
-        self.env.have_changed_path()
-    }
-
-    pub fn setup_io(
-        &self,
-        default: Stdio,
-        needs_stdin: bool,
-    ) -> io::Result<(StdioPipes, ChildPipes)> {
-        let null = Stdio::Null;
-        let default_stdin = if needs_stdin { &default } else { &null };
-        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
-        let stdout = self.stdout.as_ref().unwrap_or(&default);
-        let stderr = self.stderr.as_ref().unwrap_or(&default);
-        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
-        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
-        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
-        let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr };
-        let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr };
-        Ok((ours, theirs))
-    }
-}
-
-fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
-    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
-        *saw_nul = true;
-        CString::new("<string-with-nul>").unwrap()
-    })
-}
-
-// Helper type to manage ownership of the strings within a C-style array.
-pub struct CStringArray {
-    items: Vec<CString>,
-    ptrs: Vec<*const c_char>,
-}
-
-impl CStringArray {
-    pub fn with_capacity(capacity: usize) -> Self {
-        let mut result = CStringArray {
-            items: Vec::with_capacity(capacity),
-            ptrs: Vec::with_capacity(capacity + 1),
-        };
-        result.ptrs.push(ptr::null());
-        result
-    }
-    pub fn push(&mut self, item: CString) {
-        let l = self.ptrs.len();
-        self.ptrs[l - 1] = item.as_ptr();
-        self.ptrs.push(ptr::null());
-        self.items.push(item);
-    }
-    pub fn as_ptr(&self) -> *const *const c_char {
-        self.ptrs.as_ptr()
-    }
-}
-
-fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray {
-    let mut result = CStringArray::with_capacity(env.len());
-    for (k, v) in env {
-        let mut k: OsString = k.into();
-
-        // Reserve additional space for '=' and null terminator
-        k.reserve_exact(v.len() + 2);
-        k.push("=");
-        k.push(&v);
-
-        // Add the new entry into the array
-        if let Ok(item) = CString::new(k.into_vec()) {
-            result.push(item);
-        } else {
-            *saw_nul = true;
-        }
-    }
-
-    result
-}
-
-impl Stdio {
-    pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<AnonPipe>)> {
-        match *self {
-            Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
-
-            // Make sure that the source descriptors are not an stdio
-            // descriptor, otherwise the order which we set the child's
-            // descriptors may blow away a descriptor which we are hoping to
-            // save. For example, suppose we want the child's stderr to be the
-            // parent's stdout, and the child's stdout to be the parent's
-            // stderr. No matter which we dup first, the second will get
-            // overwritten prematurely.
-            Stdio::Fd(ref fd) => {
-                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
-                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
-                } else {
-                    Ok((ChildStdio::Explicit(fd.raw()), None))
-                }
-            }
-
-            Stdio::MakePipe => {
-                let (reader, writer) = pipe::anon_pipe()?;
-                let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) };
-                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
-            }
-
-            Stdio::Null => {
-                let mut opts = OpenOptions::new();
-                opts.read(readable);
-                opts.write(!readable);
-                let path = unsafe { CStr::from_ptr("/null\0".as_ptr() as *const _) };
-                let fd = File::open_c(&path, &opts)?;
-                Ok((ChildStdio::Owned(fd.into_fd()), None))
-            }
-        }
-    }
-}
-
-impl From<AnonPipe> for Stdio {
-    fn from(pipe: AnonPipe) -> Stdio {
-        Stdio::Fd(pipe.into_fd())
-    }
-}
-
-impl From<File> for Stdio {
-    fn from(file: File) -> Stdio {
-        Stdio::Fd(file.into_fd())
-    }
-}
-
-impl ChildStdio {
-    pub fn fd(&self) -> Option<c_int> {
-        match *self {
-            ChildStdio::Inherit => None,
-            ChildStdio::Explicit(fd) => Some(fd),
-            ChildStdio::Owned(ref fd) => Some(fd.raw()),
-        }
-    }
-}
-
-impl fmt::Debug for Command {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.program != self.args[0] {
-            write!(f, "[{:?}] ", self.program)?;
-        }
-        write!(f, "{:?}", self.args[0])?;
-
-        for arg in &self.args[1..] {
-            write!(f, " {:?}", arg)?;
-        }
-        Ok(())
-    }
-}
-
-/// Unix exit statuses
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatus(c_int);
-
-impl ExitStatus {
-    pub fn new(status: c_int) -> ExitStatus {
-        ExitStatus(status)
-    }
-
-    fn exited(&self) -> bool {
-        libc::WIFEXITED(self.0)
-    }
-
-    pub fn success(&self) -> bool {
-        self.code() == Some(0)
-    }
-
-    pub fn code(&self) -> Option<i32> {
-        if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None }
-    }
-
-    pub fn signal(&self) -> Option<i32> {
-        if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None }
-    }
-}
-
-/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
-impl From<c_int> for ExitStatus {
-    fn from(a: c_int) -> ExitStatus {
-        ExitStatus(a)
-    }
-}
-
-impl fmt::Display for ExitStatus {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let Some(code) = self.code() {
-            write!(f, "exit code: {}", code)
-        } else {
-            let signal = self.signal().unwrap();
-            write!(f, "signal: {}", signal)
-        }
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(u8);
-
-impl ExitCode {
-    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
-    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
-
-    #[inline]
-    pub fn as_i32(&self) -> i32 {
-        self.0 as i32
-    }
-}
diff --git a/library/std/src/sys/vxworks/process/process_vxworks.rs b/library/std/src/sys/vxworks/process/process_vxworks.rs
index f7e84ae..69adbcd 100644
--- a/library/std/src/sys/vxworks/process/process_vxworks.rs
+++ b/library/std/src/sys/vxworks/process/process_vxworks.rs
@@ -1,3 +1,4 @@
+use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::sys;
 use crate::sys::cvt;
@@ -67,7 +68,7 @@
             let _lock = sys::os::env_lock();
 
             let ret = libc::rtpSpawn(
-                self.get_program().as_ptr(),
+                self.get_program_cstr().as_ptr(),
                 self.get_argv().as_ptr() as *mut *const c_char, // argv
                 c_envp as *mut *const c_char,
                 100 as c_int, // initial priority
@@ -167,3 +168,47 @@
         }
     }
 }
+
+/// Unix exit statuses
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(c_int);
+
+impl ExitStatus {
+    pub fn new(status: c_int) -> ExitStatus {
+        ExitStatus(status)
+    }
+
+    fn exited(&self) -> bool {
+        libc::WIFEXITED(self.0)
+    }
+
+    pub fn success(&self) -> bool {
+        self.code() == Some(0)
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None }
+    }
+
+    pub fn signal(&self) -> Option<i32> {
+        if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None }
+    }
+}
+
+/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
+impl From<c_int> for ExitStatus {
+    fn from(a: c_int) -> ExitStatus {
+        ExitStatus(a)
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(code) = self.code() {
+            write!(f, "exit code: {}", code)
+        } else {
+            let signal = self.signal().unwrap();
+            write!(f, "signal: {}", signal)
+        }
+    }
+}
diff --git a/library/std/src/sys/vxworks/rwlock.rs b/library/std/src/sys/vxworks/rwlock.rs
deleted file mode 100644
index c90304c..0000000
--- a/library/std/src/sys/vxworks/rwlock.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sync::atomic::{AtomicUsize, Ordering};
-
-pub struct RWLock {
-    inner: UnsafeCell<libc::pthread_rwlock_t>,
-    write_locked: UnsafeCell<bool>,
-    num_readers: AtomicUsize,
-}
-
-unsafe impl Send for RWLock {}
-unsafe impl Sync for RWLock {}
-
-impl RWLock {
-    pub const fn new() -> RWLock {
-        RWLock {
-            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
-            write_locked: UnsafeCell::new(false),
-            num_readers: AtomicUsize::new(0),
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        let r = libc::pthread_rwlock_rdlock(self.inner.get());
-        if r == libc::EAGAIN {
-            panic!("rwlock maximum reader count exceeded");
-        } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) {
-            if r == 0 {
-                self.raw_unlock();
-            }
-            panic!("rwlock read lock would result in deadlock");
-        } else {
-            debug_assert_eq!(r, 0);
-            self.num_readers.fetch_add(1, Ordering::Relaxed);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
-        if r == 0 {
-            if *self.write_locked.get() {
-                self.raw_unlock();
-                false
-            } else {
-                self.num_readers.fetch_add(1, Ordering::Relaxed);
-                true
-            }
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        let r = libc::pthread_rwlock_wrlock(self.inner.get());
-        // See comments above for why we check for EDEADLK and write_locked. We
-        // also need to check that num_readers is 0.
-        if r == libc::EDEADLK
-            || *self.write_locked.get()
-            || self.num_readers.load(Ordering::Relaxed) != 0
-        {
-            if r == 0 {
-                self.raw_unlock();
-            }
-            panic!("rwlock write lock would result in deadlock");
-        } else {
-            debug_assert_eq!(r, 0);
-        }
-        *self.write_locked.get() = true;
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        let r = libc::pthread_rwlock_trywrlock(self.inner.get());
-        if r == 0 {
-            if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
-                self.raw_unlock();
-                false
-            } else {
-                *self.write_locked.get() = true;
-                true
-            }
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    unsafe fn raw_unlock(&self) {
-        let r = libc::pthread_rwlock_unlock(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        debug_assert!(!*self.write_locked.get());
-        self.num_readers.fetch_sub(1, Ordering::Relaxed);
-        self.raw_unlock();
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
-        debug_assert!(*self.write_locked.get());
-        *self.write_locked.get() = false;
-        self.raw_unlock();
-    }
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        let r = libc::pthread_rwlock_destroy(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-}
diff --git a/library/std/src/sys/vxworks/stack_overflow.rs b/library/std/src/sys/vxworks/stack_overflow.rs
deleted file mode 100644
index 7b58c83..0000000
--- a/library/std/src/sys/vxworks/stack_overflow.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-#![cfg_attr(test, allow(dead_code))]
-
-use self::imp::{drop_handler, make_handler};
-
-pub use self::imp::cleanup;
-pub use self::imp::init;
-
-pub struct Handler {
-    _data: *mut libc::c_void,
-}
-
-impl Handler {
-    pub unsafe fn new() -> Handler {
-        make_handler()
-    }
-}
-
-impl Drop for Handler {
-    fn drop(&mut self) {
-        unsafe {
-            drop_handler(self);
-        }
-    }
-}
-
-mod imp {
-    use crate::ptr;
-
-    pub unsafe fn init() {}
-
-    pub unsafe fn cleanup() {}
-
-    pub unsafe fn make_handler() -> super::Handler {
-        super::Handler { _data: ptr::null_mut() }
-    }
-
-    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
-}
diff --git a/library/std/src/sys/vxworks/stdio.rs b/library/std/src/sys/vxworks/stdio.rs
deleted file mode 100644
index 92e9f20..0000000
--- a/library/std/src/sys/vxworks/stdio.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use crate::io;
-use crate::sys::fd::FileDesc;
-
-pub struct Stdin(());
-pub struct Stdout(());
-pub struct Stderr(());
-
-impl Stdin {
-    pub const fn new() -> Stdin {
-        Stdin(())
-    }
-}
-
-impl io::Read for Stdin {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        let fd = FileDesc::new(libc::STDIN_FILENO);
-        let ret = fd.read(buf);
-        fd.into_raw(); // do not close this FD
-        ret
-    }
-}
-
-impl Stdout {
-    pub const fn new() -> Stdout {
-        Stdout(())
-    }
-}
-
-impl io::Write for Stdout {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        let fd = FileDesc::new(libc::STDOUT_FILENO);
-        let ret = fd.write(buf);
-        fd.into_raw(); // do not close this FD
-        ret
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-impl Stderr {
-    pub const fn new() -> Stderr {
-        Stderr(())
-    }
-}
-
-impl io::Write for Stderr {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        let fd = FileDesc::new(libc::STDERR_FILENO);
-        let ret = fd.write(buf);
-        fd.into_raw(); // do not close this FD
-        ret
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-pub fn is_ebadf(err: &io::Error) -> bool {
-    err.raw_os_error() == Some(libc::EBADF as i32)
-}
-
-pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
-
-pub fn panic_output() -> Option<impl io::Write> {
-    Some(Stderr::new())
-}
diff --git a/library/std/src/sys/vxworks/thread.rs b/library/std/src/sys/vxworks/thread.rs
deleted file mode 100644
index 24a2e0f..0000000
--- a/library/std/src/sys/vxworks/thread.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use crate::cmp;
-use crate::ffi::CStr;
-use crate::io;
-use crate::mem;
-use crate::ptr;
-use crate::sys::{os, stack_overflow};
-use crate::time::Duration;
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K
-
-pub struct Thread {
-    id: libc::pthread_t,
-}
-
-// Some platforms may have pthread_t as a pointer in which case we still want
-// a thread to be Send/Sync
-unsafe impl Send for Thread {}
-unsafe impl Sync for Thread {}
-
-// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
-// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
-unsafe fn pthread_attr_setstacksize(
-    attr: *mut libc::pthread_attr_t,
-    stack_size: libc::size_t,
-) -> libc::c_int {
-    libc::pthread_attr_setstacksize(attr, stack_size)
-}
-
-impl Thread {
-    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-        let p = Box::into_raw(box p);
-        let mut native: libc::pthread_t = mem::zeroed();
-        let mut attr: libc::pthread_attr_t = mem::zeroed();
-        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
-
-        let stack_size = cmp::max(stack, min_stack_size(&attr));
-
-        match pthread_attr_setstacksize(&mut attr, stack_size) {
-            0 => {}
-            n => {
-                assert_eq!(n, libc::EINVAL);
-                // EINVAL means |stack_size| is either too small or not a
-                // multiple of the system page size.  Because it's definitely
-                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
-                // Round up to the nearest page and try again.
-                let page_size = os::page_size();
-                let stack_size =
-                    (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
-                assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
-            }
-        };
-
-        let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
-        // Note: if the thread creation fails and this assert fails, then p will
-        // be leaked. However, an alternative design could cause double-free
-        // which is clearly worse.
-        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
-
-        return if ret != 0 {
-            // The thread failed to start and as a result p was not consumed. Therefore, it is
-            // safe to reconstruct the box so that it gets deallocated.
-            drop(Box::from_raw(p));
-            Err(io::Error::from_raw_os_error(ret))
-        } else {
-            Ok(Thread { id: native })
-        };
-
-        extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
-            unsafe {
-                // Next, set up our stack overflow handler which may get triggered if we run
-                // out of stack.
-                let _handler = stack_overflow::Handler::new();
-                // Finally, let's run some code.
-                Box::from_raw(main as *mut Box<dyn FnOnce()>)();
-            }
-            ptr::null_mut()
-        }
-    }
-
-    pub fn yield_now() {
-        let ret = unsafe { libc::sched_yield() };
-        debug_assert_eq!(ret, 0);
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // VxWorks does not provide a way to set the task name except at creation time
-    }
-
-    pub fn sleep(dur: Duration) {
-        let mut secs = dur.as_secs();
-        let mut nsecs = dur.subsec_nanos() as _;
-
-        // If we're awoken with a signal then the return value will be -1 and
-        // nanosleep will fill in `ts` with the remaining time.
-        unsafe {
-            while secs > 0 || nsecs > 0 {
-                let mut ts = libc::timespec {
-                    tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
-                    tv_nsec: nsecs,
-                };
-                secs -= ts.tv_sec as u64;
-                if libc::nanosleep(&ts, &mut ts) == -1 {
-                    assert_eq!(os::errno(), libc::EINTR);
-                    secs += ts.tv_sec as u64;
-                    nsecs = ts.tv_nsec;
-                } else {
-                    nsecs = 0;
-                }
-            }
-        }
-    }
-
-    pub fn join(self) {
-        unsafe {
-            let ret = libc::pthread_join(self.id, ptr::null_mut());
-            mem::forget(self);
-            assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
-        }
-    }
-
-    pub fn id(&self) -> libc::pthread_t {
-        self.id
-    }
-
-    pub fn into_id(self) -> libc::pthread_t {
-        let id = self.id;
-        mem::forget(self);
-        id
-    }
-}
-
-impl Drop for Thread {
-    fn drop(&mut self) {
-        let ret = unsafe { libc::pthread_detach(self.id) };
-        debug_assert_eq!(ret, 0);
-    }
-}
-
-#[cfg_attr(test, allow(dead_code))]
-pub mod guard {
-    use crate::ops::Range;
-    pub type Guard = Range<usize>;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn deinit() {}
-}
-
-fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
-    libc::PTHREAD_STACK_MIN
-}
diff --git a/library/std/src/sys/vxworks/thread_local_key.rs b/library/std/src/sys/vxworks/thread_local_key.rs
deleted file mode 100644
index 2c5b94b..0000000
--- a/library/std/src/sys/vxworks/thread_local_key.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-#![allow(dead_code)] // not used on all platforms
-
-use crate::mem;
-
-pub type Key = libc::pthread_key_t;
-
-#[inline]
-pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
-    let mut key = 0;
-    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
-    key
-}
-
-#[inline]
-pub unsafe fn set(key: Key, value: *mut u8) {
-    let r = libc::pthread_setspecific(key, value as *mut _);
-    debug_assert_eq!(r, 0);
-}
-
-#[inline]
-pub unsafe fn get(key: Key) -> *mut u8 {
-    libc::pthread_getspecific(key) as *mut u8
-}
-
-#[inline]
-pub unsafe fn destroy(key: Key) {
-    let r = libc::pthread_key_delete(key);
-    debug_assert_eq!(r, 0);
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
-    false
-}
diff --git a/library/std/src/sys/vxworks/time.rs b/library/std/src/sys/vxworks/time.rs
deleted file mode 100644
index 8f46f4d..0000000
--- a/library/std/src/sys/vxworks/time.rs
+++ /dev/null
@@ -1,197 +0,0 @@
-use crate::cmp::Ordering;
-use crate::time::Duration;
-use core::hash::{Hash, Hasher};
-
-pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
-use crate::convert::TryInto;
-
-const NSEC_PER_SEC: u64 = 1_000_000_000;
-
-#[derive(Copy, Clone)]
-struct Timespec {
-    t: libc::timespec,
-}
-
-impl Timespec {
-    const fn zero() -> Timespec {
-        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
-    }
-    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
-        if self >= other {
-            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
-                Duration::new(
-                    (self.t.tv_sec - other.t.tv_sec) as u64,
-                    (self.t.tv_nsec - other.t.tv_nsec) as u32,
-                )
-            } else {
-                Duration::new(
-                    (self.t.tv_sec - 1 - other.t.tv_sec) as u64,
-                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
-                )
-            })
-        } else {
-            match other.sub_timespec(self) {
-                Ok(d) => Err(d),
-                Err(d) => Ok(d),
-            }
-        }
-    }
-
-    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
-
-        // Nano calculations can't overflow because nanos are <1B which fit
-        // in a u32.
-        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
-        if nsec >= NSEC_PER_SEC as u32 {
-            nsec -= NSEC_PER_SEC as u32;
-            secs = secs.checked_add(1)?;
-        }
-        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
-    }
-
-    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
-
-        // Similar to above, nanos can't overflow.
-        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
-        if nsec < 0 {
-            nsec += NSEC_PER_SEC as i32;
-            secs = secs.checked_sub(1)?;
-        }
-        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
-    }
-}
-
-impl PartialEq for Timespec {
-    fn eq(&self, other: &Timespec) -> bool {
-        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
-    }
-}
-
-impl Eq for Timespec {}
-
-impl PartialOrd for Timespec {
-    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for Timespec {
-    fn cmp(&self, other: &Timespec) -> Ordering {
-        let me = (self.t.tv_sec, self.t.tv_nsec);
-        let other = (other.t.tv_sec, other.t.tv_nsec);
-        me.cmp(&other)
-    }
-}
-
-impl Hash for Timespec {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.t.tv_sec.hash(state);
-        self.t.tv_nsec.hash(state);
-    }
-}
-mod inner {
-    use crate::fmt;
-    use crate::sys::cvt;
-    use crate::time::Duration;
-
-    use super::Timespec;
-
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct Instant {
-        t: Timespec,
-    }
-
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct SystemTime {
-        t: Timespec,
-    }
-
-    pub const UNIX_EPOCH: SystemTime =
-        SystemTime { t: Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } };
-
-    impl Instant {
-        pub fn now() -> Instant {
-            Instant { t: now(libc::CLOCK_MONOTONIC) }
-        }
-
-        pub const fn zero() -> Instant {
-            Instant { t: Timespec::zero() }
-        }
-
-        pub fn actually_monotonic() -> bool {
-            true
-        }
-
-        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
-            self.t.sub_timespec(&other.t).ok()
-        }
-
-        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_add_duration(other)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_sub_duration(other)? })
-        }
-    }
-
-    impl fmt::Debug for Instant {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.debug_struct("Instant")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
-                .finish()
-        }
-    }
-
-    impl SystemTime {
-        pub fn now() -> SystemTime {
-            SystemTime { t: now(libc::CLOCK_REALTIME) }
-        }
-
-        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-            self.t.sub_timespec(&other.t)
-        }
-
-        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-            Some(SystemTime { t: self.t.checked_add_duration(other)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
-        }
-    }
-
-    impl From<libc::timespec> for SystemTime {
-        fn from(t: libc::timespec) -> SystemTime {
-            SystemTime { t: Timespec { t: t } }
-        }
-    }
-
-    impl fmt::Debug for SystemTime {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.debug_struct("SystemTime")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
-                .finish()
-        }
-    }
-
-    pub type clock_t = libc::c_int;
-
-    fn now(clock: clock_t) -> Timespec {
-        let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
-        cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
-        t
-    }
-}
diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs
index 4e8fa65..81413f3 100644
--- a/library/std/src/sys/wasi/ext/io.rs
+++ b/library/std/src/sys/wasi/ext/io.rs
@@ -52,6 +52,25 @@
     fn into_raw_fd(self) -> RawFd;
 }
 
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
 impl AsRawFd for net::TcpStream {
     fn as_raw_fd(&self) -> RawFd {
         self.as_inner().fd().as_raw()
@@ -141,3 +160,21 @@
         sys::stdio::Stderr.as_raw_fd()
     }
 }
+
+impl<'a> AsRawFd for io::StdinLock<'a> {
+    fn as_raw_fd(&self) -> RawFd {
+        sys::stdio::Stdin.as_raw_fd()
+    }
+}
+
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+    fn as_raw_fd(&self) -> RawFd {
+        sys::stdio::Stdout.as_raw_fd()
+    }
+}
+
+impl<'a> AsRawFd for io::StderrLock<'a> {
+    fn as_raw_fd(&self) -> RawFd {
+        sys::stdio::Stderr.as_raw_fd()
+    }
+}
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index a7a4407..a0a37ef 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -53,6 +53,7 @@
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
+#[deny(unsafe_op_in_unsafe_fn)]
 #[allow(unused)]
 mod common;
 pub use common::*;
diff --git a/library/std/src/sys/wasm/condvar_atomics.rs b/library/std/src/sys/wasm/condvar_atomics.rs
index d86bb60..a96bb18 100644
--- a/library/std/src/sys/wasm/condvar_atomics.rs
+++ b/library/std/src/sys/wasm/condvar_atomics.rs
@@ -9,6 +9,8 @@
     cnt: AtomicUsize,
 }
 
+pub type MovableCondvar = Condvar;
+
 // Condition variables are implemented with a simple counter internally that is
 // likely to cause spurious wakeups. Blocking on a condition variable will first
 // read the value of the internal counter, unlock the given mutex, and then
diff --git a/library/std/src/sys/wasm/futex_atomics.rs b/library/std/src/sys/wasm/futex_atomics.rs
new file mode 100644
index 0000000..3d8bf42
--- /dev/null
+++ b/library/std/src/sys/wasm/futex_atomics.rs
@@ -0,0 +1,17 @@
+use crate::arch::wasm32;
+use crate::convert::TryInto;
+use crate::sync::atomic::AtomicI32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
+    let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
+    unsafe {
+        wasm32::memory_atomic_wait32(futex as *const AtomicI32 as *mut i32, expected, timeout);
+    }
+}
+
+pub fn futex_wake(futex: &AtomicI32) {
+    unsafe {
+        wasm32::memory_atomic_notify(futex as *const AtomicI32 as *mut i32, 1);
+    }
+}
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index 2934ea5..11c6896 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -55,6 +55,8 @@
         pub mod mutex;
         #[path = "rwlock_atomics.rs"]
         pub mod rwlock;
+        #[path = "futex_atomics.rs"]
+        pub mod futex;
     } else {
         #[path = "../unsupported/condvar.rs"]
         pub mod condvar;
@@ -66,5 +68,6 @@
 }
 
 #[path = "../unsupported/common.rs"]
+#[deny(unsafe_op_in_unsafe_fn)]
 mod common;
 pub use common::*;
diff --git a/library/std/src/sys/wasm/mutex_atomics.rs b/library/std/src/sys/wasm/mutex_atomics.rs
index 4b1a7c9..2970fcf 100644
--- a/library/std/src/sys/wasm/mutex_atomics.rs
+++ b/library/std/src/sys/wasm/mutex_atomics.rs
@@ -8,6 +8,8 @@
     locked: AtomicUsize,
 }
 
+pub type MovableMutex = Mutex;
+
 // Mutexes have a pretty simple implementation where they contain an `i32`
 // internally that is 0 when unlocked and 1 when the mutex is locked.
 // Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index f440442..657421e 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -47,7 +47,6 @@
 pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
 pub type LPWSADATA = *mut WSADATA;
 pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
-pub type LPSTR = *mut CHAR;
 pub type LPWSTR = *mut WCHAR;
 pub type LPFILETIME = *mut FILETIME;
 pub type LPWSABUF = *mut WSABUF;
@@ -876,16 +875,6 @@
     pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
     pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
     pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
-    pub fn WideCharToMultiByte(
-        CodePage: UINT,
-        dwFlags: DWORD,
-        lpWideCharStr: LPCWSTR,
-        cchWideChar: c_int,
-        lpMultiByteStr: LPSTR,
-        cbMultiByte: c_int,
-        lpDefaultChar: LPCSTR,
-        lpUsedDefaultChar: LPBOOL,
-    ) -> c_int;
 
     pub fn closesocket(socket: SOCKET) -> c_int;
     pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
@@ -1032,7 +1021,7 @@
 // Functions that aren't available on every version of Windows that we support,
 // but we still use them and just provide some form of a fallback implementation.
 compat_fn! {
-    kernel32:
+    "kernel32":
 
     pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
                                _lpTargetFileName: LPCWSTR,
diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs
index d6d433f..3f25f05 100644
--- a/library/std/src/sys/windows/compat.rs
+++ b/library/std/src/sys/windows/compat.rs
@@ -12,7 +12,6 @@
 //! function is available but afterwards it's just a load and a jump.
 
 use crate::ffi::CString;
-use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::c;
 
 pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
@@ -28,45 +27,69 @@
     }
 }
 
-pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize {
-    let value = lookup(module, symbol).unwrap_or(fallback);
-    ptr.store(value, Ordering::SeqCst);
-    value
-}
-
 macro_rules! compat_fn {
-    ($module:ident: $(
+    ($module:literal: $(
         $(#[$meta:meta])*
-        pub fn $symbol:ident($($argname:ident: $argtype:ty),*)
-                                  -> $rettype:ty {
-            $($body:expr);*
-        }
+        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block
     )*) => ($(
-        #[allow(unused_variables)]
         $(#[$meta])*
-        pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
+        pub mod $symbol {
+            use super::*;
             use crate::sync::atomic::{AtomicUsize, Ordering};
             use crate::mem;
+
             type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
 
             static PTR: AtomicUsize = AtomicUsize::new(0);
 
+            #[allow(unused_variables)]
+            unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body
+
+            /// This address is stored in `PTR` to incidate an unavailable API.
+            ///
+            /// This way, call() will end up calling fallback() if it is unavailable.
+            ///
+            /// This is a `static` to avoid rustc duplicating `fn fallback()`
+            /// into both load() and is_available(), which would break
+            /// is_available()'s comparison. By using the same static variable
+            /// in both places, they'll refer to the same (copy of the)
+            /// function.
+            ///
+            /// LLVM merging the address of fallback with other functions
+            /// (because of unnamed_addr) is fine, since it's only compared to
+            /// an address from GetProcAddress from an external dll.
+            static FALLBACK: F = fallback;
+
+            #[cold]
             fn load() -> usize {
-                crate::sys::compat::store_func(&PTR,
-                                          stringify!($module),
-                                          stringify!($symbol),
-                                          fallback as usize)
-            }
-            unsafe extern "system" fn fallback($($argname: $argtype),*)
-                                               -> $rettype {
-                $($body);*
+                // There is no locking here. It's okay if this is executed by multiple threads in
+                // parallel. `lookup` will result in the same value, and it's okay if they overwrite
+                // eachothers result as long as they do so atomically. We don't need any guarantees
+                // about memory ordering, as this involves just a single atomic variable which is
+                // not used to protect or order anything else.
+                let addr = crate::sys::compat::lookup($module, stringify!($symbol))
+                    .unwrap_or(FALLBACK as usize);
+                PTR.store(addr, Ordering::Relaxed);
+                addr
             }
 
-            let addr = match PTR.load(Ordering::SeqCst) {
-                0 => load(),
-                n => n,
-            };
-            mem::transmute::<usize, F>(addr)($($argname),*)
+            fn addr() -> usize {
+                match PTR.load(Ordering::Relaxed) {
+                    0 => load(),
+                    addr => addr,
+                }
+            }
+
+            #[allow(dead_code)]
+            pub fn is_available() -> bool {
+                addr() != FALLBACK as usize
+            }
+
+            pub unsafe fn call($($argname: $argtype),*) -> $rettype {
+                mem::transmute::<usize, F>(addr())($($argname),*)
+            }
         }
+
+        pub use $symbol::call as $symbol;
     )*)
 }
diff --git a/library/std/src/sys/windows/condvar.rs b/library/std/src/sys/windows/condvar.rs
index 8f7f685..44547a5 100644
--- a/library/std/src/sys/windows/condvar.rs
+++ b/library/std/src/sys/windows/condvar.rs
@@ -8,6 +8,8 @@
     inner: UnsafeCell<c::CONDITION_VARIABLE>,
 }
 
+pub type MovableCondvar = Condvar;
+
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 8178e68..8c19cc7 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -4,7 +4,6 @@
 use crate::io::ErrorKind;
 use crate::os::windows::ffi::{OsStrExt, OsStringExt};
 use crate::path::PathBuf;
-use crate::ptr;
 use crate::time::Duration;
 
 pub use self::rand::hashmap_random_keys;
@@ -206,58 +205,6 @@
     PathBuf::from(OsString::from_wide(s))
 }
 
-#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
-fn wide_char_to_multi_byte(
-    code_page: u32,
-    flags: u32,
-    s: &[u16],
-    no_default_char: bool,
-) -> crate::io::Result<Vec<i8>> {
-    unsafe {
-        let mut size = c::WideCharToMultiByte(
-            code_page,
-            flags,
-            s.as_ptr(),
-            s.len() as i32,
-            ptr::null_mut(),
-            0,
-            ptr::null(),
-            ptr::null_mut(),
-        );
-        if size == 0 {
-            return Err(crate::io::Error::last_os_error());
-        }
-
-        let mut buf = Vec::with_capacity(size as usize);
-        buf.set_len(size as usize);
-
-        let mut used_default_char = c::FALSE;
-        size = c::WideCharToMultiByte(
-            code_page,
-            flags,
-            s.as_ptr(),
-            s.len() as i32,
-            buf.as_mut_ptr(),
-            buf.len() as i32,
-            ptr::null(),
-            if no_default_char { &mut used_default_char } else { ptr::null_mut() },
-        );
-        if size == 0 {
-            return Err(crate::io::Error::last_os_error());
-        }
-        if no_default_char && used_default_char == c::TRUE {
-            return Err(crate::io::Error::new(
-                crate::io::ErrorKind::InvalidData,
-                "string cannot be converted to requested code page",
-            ));
-        }
-
-        buf.set_len(size as usize);
-
-        Ok(buf)
-    }
-}
-
 pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
     match unrolled_find_u16s(0, v) {
         // don't include the 0
diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs
index 1e09b95..fa51b00 100644
--- a/library/std/src/sys/windows/mutex.rs
+++ b/library/std/src/sys/windows/mutex.rs
@@ -23,13 +23,17 @@
 use crate::mem::{self, MaybeUninit};
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::c;
-use crate::sys::compat;
 
 pub struct Mutex {
     // This is either directly an SRWLOCK (if supported), or a Box<Inner> otherwise.
     lock: AtomicUsize,
 }
 
+// Windows SRW Locks are movable (while not borrowed).
+// ReentrantMutexes (in Inner) are not, but those are stored indirectly through
+// a Box, so do not move when the Mutex it self is moved.
+pub type MovableMutex = Mutex;
+
 unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {}
 
@@ -40,8 +44,8 @@
 
 #[derive(Clone, Copy)]
 enum Kind {
-    SRWLock = 1,
-    CriticalSection = 2,
+    SRWLock,
+    CriticalSection,
 }
 
 #[inline]
@@ -130,21 +134,7 @@
 }
 
 fn kind() -> Kind {
-    static KIND: AtomicUsize = AtomicUsize::new(0);
-
-    let val = KIND.load(Ordering::SeqCst);
-    if val == Kind::SRWLock as usize {
-        return Kind::SRWLock;
-    } else if val == Kind::CriticalSection as usize {
-        return Kind::CriticalSection;
-    }
-
-    let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") {
-        None => Kind::CriticalSection,
-        Some(..) => Kind::SRWLock,
-    };
-    KIND.store(ret as usize, Ordering::SeqCst);
-    ret
+    if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection }
 }
 
 pub struct ReentrantMutex {
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index e18521b..243065b 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -22,7 +22,7 @@
 use crate::sys::mutex::Mutex;
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::stdio;
-use crate::sys_common::process::CommandEnv;
+use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::sys_common::AsInner;
 
 use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
@@ -134,6 +134,23 @@
         self.flags = flags;
     }
 
+    pub fn get_program(&self) -> &OsStr {
+        &self.program
+    }
+
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        let iter = self.args.iter();
+        CommandArgs { iter }
+    }
+
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        self.env.iter()
+    }
+
+    pub fn get_current_dir(&self) -> Option<&Path> {
+        self.cwd.as_ref().map(|cwd| Path::new(cwd))
+    }
+
     pub fn spawn(
         &mut self,
         default: Stdio,
@@ -529,3 +546,32 @@
         None => Ok((ptr::null(), Vec::new())),
     }
 }
+
+pub struct CommandArgs<'a> {
+    iter: crate::slice::Iter<'a, OsString>,
+}
+
+impl<'a> Iterator for CommandArgs<'a> {
+    type Item = &'a OsStr;
+    fn next(&mut self) -> Option<&'a OsStr> {
+        self.iter.next().map(|s| s.as_ref())
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+impl<'a> ExactSizeIterator for CommandArgs<'a> {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+impl<'a> fmt::Debug for CommandArgs<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.iter.clone()).finish()
+    }
+}
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index 9002601..91e4f76 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -165,7 +165,7 @@
 
 mod perf_counter {
     use super::NANOS_PER_SEC;
-    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+    use crate::sync::atomic::{AtomicU64, Ordering};
     use crate::sys::c;
     use crate::sys::cvt;
     use crate::sys_common::mul_div_u64;
@@ -197,27 +197,25 @@
     }
 
     fn frequency() -> c::LARGE_INTEGER {
-        static mut FREQUENCY: c::LARGE_INTEGER = 0;
-        static STATE: AtomicUsize = AtomicUsize::new(0);
+        // Either the cached result of `QueryPerformanceFrequency` or `0` for
+        // uninitialized. Storing this as a single `AtomicU64` allows us to use
+        // `Relaxed` operations, as we are only interested in the effects on a
+        // single memory location.
+        static FREQUENCY: AtomicU64 = AtomicU64::new(0);
 
-        unsafe {
-            // If a previous thread has filled in this global state, use that.
-            if STATE.load(SeqCst) == 2 {
-                return FREQUENCY;
-            }
-
-            // ... otherwise learn for ourselves ...
-            let mut frequency = 0;
-            cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap();
-
-            // ... and attempt to be the one thread that stores it globally for
-            // all other threads
-            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
-                FREQUENCY = frequency;
-                STATE.store(2, SeqCst);
-            }
-            frequency
+        let cached = FREQUENCY.load(Ordering::Relaxed);
+        // If a previous thread has filled in this global state, use that.
+        if cached != 0 {
+            return cached as c::LARGE_INTEGER;
         }
+        // ... otherwise learn for ourselves ...
+        let mut frequency = 0;
+        unsafe {
+            cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap();
+        }
+
+        FREQUENCY.store(frequency as u64, Ordering::Relaxed);
+        frequency
     }
 
     fn query() -> c::LARGE_INTEGER {
diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs
index f22476b..6c1bc0d 100644
--- a/library/std/src/sys_common/alloc.rs
+++ b/library/std/src/sys_common/alloc.rs
@@ -12,6 +12,7 @@
     target_arch = "mips",
     target_arch = "powerpc",
     target_arch = "powerpc64",
+    target_arch = "sparc",
     target_arch = "asmjs",
     target_arch = "wasm32",
     target_arch = "hexagon",
diff --git a/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs
index 6b799db..90d5d3a 100644
--- a/library/std/src/sys_common/at_exit_imp.rs
+++ b/library/std/src/sys_common/at_exit_imp.rs
@@ -4,7 +4,7 @@
 
 use crate::mem;
 use crate::ptr;
-use crate::sys_common::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 
 type Queue = Vec<Box<dyn FnOnce()>>;
 
@@ -12,9 +12,8 @@
 // on poisoning and this module needs to operate at a lower level than requiring
 // the thread infrastructure to be in place (useful on the borders of
 // initialization/destruction).
-// We never call `LOCK.init()`, so it is UB to attempt to
-// acquire this mutex reentrantly!
-static LOCK: Mutex = Mutex::new();
+// It is UB to attempt to acquire this mutex reentrantly!
+static LOCK: StaticMutex = StaticMutex::new();
 static mut QUEUE: *mut Queue = ptr::null_mut();
 
 const DONE: *mut Queue = 1_usize as *mut _;
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index 1c5fbf7..a549770 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -8,27 +8,15 @@
 use crate::io::prelude::*;
 use crate::path::{self, Path, PathBuf};
 use crate::sync::atomic::{self, Ordering};
-use crate::sys::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
 
-pub fn lock() -> impl Drop {
-    struct Guard;
-    static LOCK: Mutex = Mutex::new();
-
-    impl Drop for Guard {
-        fn drop(&mut self) {
-            unsafe {
-                LOCK.unlock();
-            }
-        }
-    }
-
-    unsafe {
-        LOCK.lock();
-        Guard
-    }
+// SAFETY: Don't attempt to lock this reentrantly.
+pub unsafe fn lock() -> impl Drop {
+    static LOCK: StaticMutex = StaticMutex::new();
+    LOCK.lock()
 }
 
 /// Prints the current backtrace.
diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs
index f9611bc..2c02e1c 100644
--- a/library/std/src/sys_common/condvar.rs
+++ b/library/std/src/sys_common/condvar.rs
@@ -1,72 +1,64 @@
 use crate::sys::condvar as imp;
-use crate::sys_common::mutex::{self, Mutex};
+use crate::sys::mutex as mutex_imp;
+use crate::sys_common::mutex::MovableMutex;
 use crate::time::Duration;
 
+mod check;
+
+type CondvarCheck = <mutex_imp::MovableMutex as check::CondvarCheck>::Check;
+
 /// An OS-based condition variable.
-///
-/// This structure is the lowest layer possible on top of the OS-provided
-/// condition variables. It is consequently entirely unsafe to use. It is
-/// recommended to use the safer types at the top level of this crate instead of
-/// this type.
-pub struct Condvar(imp::Condvar);
+pub struct Condvar {
+    inner: imp::MovableCondvar,
+    check: CondvarCheck,
+}
 
 impl Condvar {
     /// Creates a new condition variable for use.
-    ///
-    /// Behavior is undefined if the condition variable is moved after it is
-    /// first used with any of the functions below.
-    pub const fn new() -> Condvar {
-        Condvar(imp::Condvar::new())
-    }
-
-    /// Prepares the condition variable for use.
-    ///
-    /// This should be called once the condition variable is at a stable memory
-    /// address.
-    #[inline]
-    pub unsafe fn init(&mut self) {
-        self.0.init()
+    pub fn new() -> Self {
+        let mut c = imp::MovableCondvar::from(imp::Condvar::new());
+        unsafe { c.init() };
+        Self { inner: c, check: CondvarCheck::new() }
     }
 
     /// Signals one waiter on this condition variable to wake up.
     #[inline]
-    pub unsafe fn notify_one(&self) {
-        self.0.notify_one()
+    pub fn notify_one(&self) {
+        unsafe { self.inner.notify_one() };
     }
 
     /// Awakens all current waiters on this condition variable.
     #[inline]
-    pub unsafe fn notify_all(&self) {
-        self.0.notify_all()
+    pub fn notify_all(&self) {
+        unsafe { self.inner.notify_all() };
     }
 
     /// Waits for a signal on the specified mutex.
     ///
     /// Behavior is undefined if the mutex is not locked by the current thread.
-    /// Behavior is also undefined if more than one mutex is used concurrently
-    /// on this condition variable.
+    ///
+    /// May panic if used with more than one mutex.
     #[inline]
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.0.wait(mutex::raw(mutex))
+    pub unsafe fn wait(&self, mutex: &MovableMutex) {
+        self.check.verify(mutex);
+        self.inner.wait(mutex.raw())
     }
 
     /// Waits for a signal on the specified mutex with a timeout duration
     /// specified by `dur` (a relative time into the future).
     ///
     /// Behavior is undefined if the mutex is not locked by the current thread.
-    /// Behavior is also undefined if more than one mutex is used concurrently
-    /// on this condition variable.
-    #[inline]
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        self.0.wait_timeout(mutex::raw(mutex), dur)
-    }
-
-    /// Deallocates all resources associated with this condition variable.
     ///
-    /// Behavior is undefined if there are current or will be future users of
-    /// this condition variable.
+    /// May panic if used with more than one mutex.
     #[inline]
-    pub unsafe fn destroy(&self) {
-        self.0.destroy()
+    pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool {
+        self.check.verify(mutex);
+        self.inner.wait_timeout(mutex.raw(), dur)
+    }
+}
+
+impl Drop for Condvar {
+    fn drop(&mut self) {
+        unsafe { self.inner.destroy() };
     }
 }
diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs
new file mode 100644
index 0000000..fecb732
--- /dev/null
+++ b/library/std/src/sys_common/condvar/check.rs
@@ -0,0 +1,48 @@
+use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sys::mutex as mutex_imp;
+use crate::sys_common::mutex::MovableMutex;
+
+pub trait CondvarCheck {
+    type Check;
+}
+
+/// For boxed mutexes, a `Condvar` will check it's only ever used with the same
+/// mutex, based on its (stable) address.
+impl CondvarCheck for Box<mutex_imp::Mutex> {
+    type Check = SameMutexCheck;
+}
+
+pub struct SameMutexCheck {
+    addr: AtomicUsize,
+}
+
+#[allow(dead_code)]
+impl SameMutexCheck {
+    pub const fn new() -> Self {
+        Self { addr: AtomicUsize::new(0) }
+    }
+    pub fn verify(&self, mutex: &MovableMutex) {
+        let addr = mutex.raw() as *const mutex_imp::Mutex as usize;
+        match self.addr.compare_and_swap(0, addr, Ordering::SeqCst) {
+            0 => {}              // Stored the address
+            n if n == addr => {} // Lost a race to store the same address
+            _ => panic!("attempted to use a condition variable with two mutexes"),
+        }
+    }
+}
+
+/// Unboxed mutexes may move, so `Condvar` can not require its address to stay
+/// constant.
+impl CondvarCheck for mutex_imp::Mutex {
+    type Check = NoCheck;
+}
+
+pub struct NoCheck;
+
+#[allow(dead_code)]
+impl NoCheck {
+    pub const fn new() -> Self {
+        Self
+    }
+    pub fn verify(&self, _: &MovableMutex) {}
+}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 28cdfef..234b257 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -66,6 +66,7 @@
 pub mod thread_info;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
+pub mod thread_parker;
 pub mod util;
 pub mod wtf8;
 
diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
index e66d899..f3e7efb 100644
--- a/library/std/src/sys_common/mutex.rs
+++ b/library/std/src/sys_common/mutex.rs
@@ -1,101 +1,100 @@
 use crate::sys::mutex as imp;
 
-/// An OS-based mutual exclusion lock.
+/// An OS-based mutual exclusion lock, meant for use in static variables.
 ///
-/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
-/// this mutex is unsafe and it is recommended to instead use the safe wrapper
-/// at the top level of the crate instead of this type.
-pub struct Mutex(imp::Mutex);
+/// This mutex has a const constructor ([`StaticMutex::new`]), does not
+/// implement `Drop` to cleanup resources, and causes UB when used reentrantly.
+///
+/// This mutex does not implement poisoning.
+///
+/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and
+/// `destroy()`.
+pub struct StaticMutex(imp::Mutex);
 
-unsafe impl Sync for Mutex {}
+unsafe impl Sync for StaticMutex {}
 
-impl Mutex {
+impl StaticMutex {
     /// Creates a new mutex for use.
-    ///
-    /// Behavior is undefined if the mutex is moved after it is
-    /// first used with any of the functions below.
-    /// Also, until `init` is called, behavior is undefined if this
-    /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock`
-    /// are called by the thread currently holding the lock.
-    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
-    pub const fn new() -> Mutex {
-        Mutex(imp::Mutex::new())
-    }
-
-    /// Prepare the mutex for use.
-    ///
-    /// This should be called once the mutex is at a stable memory address.
-    /// If called, this must be the very first thing that happens to the mutex.
-    /// Calling it in parallel with or after any operation (including another
-    /// `init()`) is undefined behavior.
-    #[inline]
-    pub unsafe fn init(&mut self) {
-        self.0.init()
-    }
-
-    /// Locks the mutex blocking the current thread until it is available.
-    ///
-    /// Behavior is undefined if the mutex has been moved between this and any
-    /// previous function call.
-    #[inline]
-    pub unsafe fn raw_lock(&self) {
-        self.0.lock()
+    pub const fn new() -> Self {
+        Self(imp::Mutex::new())
     }
 
     /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
     /// will be unlocked.
+    ///
+    /// It is undefined behaviour to call this function while locked by the
+    /// same thread.
     #[inline]
-    pub unsafe fn lock(&self) -> MutexGuard<'_> {
-        self.raw_lock();
-        MutexGuard(&self.0)
+    pub unsafe fn lock(&'static self) -> StaticMutexGuard {
+        self.0.lock();
+        StaticMutexGuard(&self.0)
+    }
+}
+
+#[must_use]
+pub struct StaticMutexGuard(&'static imp::Mutex);
+
+impl Drop for StaticMutexGuard {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.0.unlock();
+        }
+    }
+}
+
+/// An OS-based mutual exclusion lock.
+///
+/// This mutex does *not* have a const constructor, cleans up its resources in
+/// its `Drop` implementation, may safely be moved (when not borrowed), and
+/// does not cause UB when used reentrantly.
+///
+/// This mutex does not implement poisoning.
+///
+/// This is either a wrapper around `Box<imp::Mutex>` or `imp::Mutex`,
+/// depending on the platform. It is boxed on platforms where `imp::Mutex` may
+/// not be moved.
+pub struct MovableMutex(imp::MovableMutex);
+
+unsafe impl Sync for MovableMutex {}
+
+impl MovableMutex {
+    /// Creates a new mutex.
+    pub fn new() -> Self {
+        let mut mutex = imp::MovableMutex::from(imp::Mutex::new());
+        unsafe { mutex.init() };
+        Self(mutex)
+    }
+
+    pub(super) fn raw(&self) -> &imp::Mutex {
+        &self.0
+    }
+
+    /// Locks the mutex blocking the current thread until it is available.
+    #[inline]
+    pub fn raw_lock(&self) {
+        unsafe { self.0.lock() }
     }
 
     /// Attempts to lock the mutex without blocking, returning whether it was
     /// successfully acquired or not.
-    ///
-    /// Behavior is undefined if the mutex has been moved between this and any
-    /// previous function call.
     #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        self.0.try_lock()
+    pub fn try_lock(&self) -> bool {
+        unsafe { self.0.try_lock() }
     }
 
     /// Unlocks the mutex.
     ///
     /// Behavior is undefined if the current thread does not actually hold the
     /// mutex.
-    ///
-    /// Consider switching from the pair of raw_lock() and raw_unlock() to
-    /// lock() whenever possible.
     #[inline]
     pub unsafe fn raw_unlock(&self) {
         self.0.unlock()
     }
-
-    /// Deallocates all resources associated with this mutex.
-    ///
-    /// Behavior is undefined if there are current or will be future users of
-    /// this mutex.
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        self.0.destroy()
-    }
 }
 
-// not meant to be exported to the outside world, just the containing module
-pub fn raw(mutex: &Mutex) -> &imp::Mutex {
-    &mutex.0
-}
-
-#[must_use]
-/// A simple RAII utility for the above Mutex without the poisoning semantics.
-pub struct MutexGuard<'a>(&'a imp::Mutex);
-
-impl Drop for MutexGuard<'_> {
-    #[inline]
+impl Drop for MovableMutex {
     fn drop(&mut self) {
-        unsafe {
-            self.0.unlock();
-        }
+        unsafe { self.0.destroy() };
     }
 }
diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs
index f3a2962..fe89b11 100644
--- a/library/std/src/sys_common/process.rs
+++ b/library/std/src/sys_common/process.rs
@@ -92,4 +92,41 @@
             self.saw_path = true;
         }
     }
+
+    pub fn iter(&self) -> CommandEnvs<'_> {
+        let iter = self.vars.iter();
+        CommandEnvs { iter }
+    }
+}
+
+/// An iterator over the command environment variables.
+///
+/// This struct is created by
+/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
+/// documentation for more.
+#[unstable(feature = "command_access", issue = "44434")]
+#[derive(Debug)]
+pub struct CommandEnvs<'a> {
+    iter: crate::collections::btree_map::Iter<'a, EnvKey, Option<OsString>>,
+}
+
+#[unstable(feature = "command_access", issue = "44434")]
+impl<'a> Iterator for CommandEnvs<'a> {
+    type Item = (&'a OsStr, Option<&'a OsStr>);
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref()))
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+#[unstable(feature = "command_access", issue = "44434")]
+impl<'a> ExactSizeIterator for CommandEnvs<'a> {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
 }
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 676eadd..dbcb7b3 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -53,7 +53,7 @@
 
 use crate::sync::atomic::{self, AtomicUsize, Ordering};
 use crate::sys::thread_local_key as imp;
-use crate::sys_common::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 
 /// A type for TLS keys that are statically allocated.
 ///
@@ -157,7 +157,7 @@
         if imp::requires_synchronized_create() {
             // We never call `INIT_LOCK.init()`, so it is UB to attempt to
             // acquire this mutex reentrantly!
-            static INIT_LOCK: Mutex = Mutex::new();
+            static INIT_LOCK: StaticMutex = StaticMutex::new();
             let _guard = INIT_LOCK.lock();
             let mut key = self.key.load(Ordering::SeqCst);
             if key == 0 {
diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs
new file mode 100644
index 0000000..a5d4927
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/futex.rs
@@ -0,0 +1,93 @@
+use crate::sync::atomic::AtomicI32;
+use crate::sync::atomic::Ordering::{Acquire, Release};
+use crate::sys::futex::{futex_wait, futex_wake};
+use crate::time::Duration;
+
+const PARKED: i32 = -1;
+const EMPTY: i32 = 0;
+const NOTIFIED: i32 = 1;
+
+pub struct Parker {
+    state: AtomicI32,
+}
+
+// Notes about memory ordering:
+//
+// Memory ordering is only relevant for the relative ordering of operations
+// between different variables. Even Ordering::Relaxed guarantees a
+// monotonic/consistent order when looking at just a single atomic variable.
+//
+// So, since this parker is just a single atomic variable, we only need to look
+// at the ordering guarantees we need to provide to the 'outside world'.
+//
+// The only memory ordering guarantee that parking and unparking provide, is
+// that things which happened before unpark() are visible on the thread
+// returning from park() afterwards. Otherwise, it was effectively unparked
+// before unpark() was called while still consuming the 'token'.
+//
+// In other words, unpark() needs to synchronize with the part of park() that
+// consumes the token and returns.
+//
+// This is done with a release-acquire synchronization, by using
+// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
+// Ordering::Acquire when checking for this state in park().
+impl Parker {
+    #[inline]
+    pub const fn new() -> Self {
+        Parker { state: AtomicI32::new(EMPTY) }
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`.
+    pub unsafe fn park(&self) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+        loop {
+            // Wait for something to happen, assuming it's still set to PARKED.
+            futex_wait(&self.state, PARKED, None);
+            // Change NOTIFIED=>EMPTY and return in that case.
+            if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
+                return;
+            } else {
+                // Spurious wake up. We loop to try again.
+            }
+        }
+    }
+
+    // Assumes this is only called by the thread that owns the Parker,
+    // which means that `self.state != PARKED`.
+    pub unsafe fn park_timeout(&self, timeout: Duration) {
+        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
+        // first case.
+        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
+            return;
+        }
+        // Wait for something to happen, assuming it's still set to PARKED.
+        futex_wait(&self.state, PARKED, Some(timeout));
+        // This is not just a store, because we need to establish a
+        // release-acquire ordering with unpark().
+        if self.state.swap(EMPTY, Acquire) == NOTIFIED {
+            // Woke up because of unpark().
+        } else {
+            // Timeout or spurious wake up.
+            // We return either way, because we can't easily tell if it was the
+            // timeout or not.
+        }
+    }
+
+    #[inline]
+    pub fn unpark(&self) {
+        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
+        // wake the thread in the first case.
+        //
+        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
+        // purpose, to make sure every unpark() has a release-acquire ordering
+        // with park().
+        if self.state.swap(NOTIFIED, Release) == PARKED {
+            futex_wake(&self.state);
+        }
+    }
+}
diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs
new file mode 100644
index 0000000..14cfa95
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/generic.rs
@@ -0,0 +1,119 @@
+//! Parker implementaiton based on a Mutex and Condvar.
+
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::{Condvar, Mutex};
+use crate::time::Duration;
+
+const EMPTY: usize = 0;
+const PARKED: usize = 1;
+const NOTIFIED: usize = 2;
+
+pub struct Parker {
+    state: AtomicUsize,
+    lock: Mutex<()>,
+    cvar: Condvar,
+}
+
+impl Parker {
+    pub fn new() -> Self {
+        Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() }
+    }
+
+    // This implementaiton doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker.
+    pub unsafe fn park(&self) {
+        // If we were previously notified then we consume this notification and
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+
+        // Otherwise we need to coordinate going to sleep
+        let mut m = self.lock.lock().unwrap();
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read here, even though we know it will be `NOTIFIED`.
+                // This is because `unpark` may have been called again since we read
+                // `NOTIFIED` in the `compare_exchange` above. We must perform an
+                // acquire operation that synchronizes with that `unpark` to observe
+                // any writes it made before the call to unpark. To do that we must
+                // read from the write it made to `state`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => panic!("inconsistent park state"),
+        }
+        loop {
+            m = self.cvar.wait(m).unwrap();
+            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+                Ok(_) => return, // got a notification
+                Err(_) => {}     // spurious wakeup, go back to sleep
+            }
+        }
+    }
+
+    // This implementaiton doesn't require `unsafe`, but other implementations
+    // may assume this is only called by the thread that owns the Parker.
+    pub unsafe fn park_timeout(&self, dur: Duration) {
+        // Like `park` above we have a fast path for an already-notified thread, and
+        // afterwards we start coordinating for a sleep.
+        // return quickly.
+        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+            return;
+        }
+        let m = self.lock.lock().unwrap();
+        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+            Ok(_) => {}
+            Err(NOTIFIED) => {
+                // We must read again here, see `park`.
+                let old = self.state.swap(EMPTY, SeqCst);
+                assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
+                return;
+            } // should consume this notification, so prohibit spurious wakeups in next park.
+            Err(_) => panic!("inconsistent park_timeout state"),
+        }
+
+        // Wait with a timeout, and if we spuriously wake up or otherwise wake up
+        // from a notification we just want to unconditionally set the state back to
+        // empty, either consuming a notification or un-flagging ourselves as
+        // parked.
+        let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap();
+        match self.state.swap(EMPTY, SeqCst) {
+            NOTIFIED => {} // got a notification, hurray!
+            PARKED => {}   // no notification, alas
+            n => panic!("inconsistent park_timeout state: {}", n),
+        }
+    }
+
+    pub fn unpark(&self) {
+        // To ensure the unparked thread will observe any writes we made
+        // before this call, we must perform a release operation that `park`
+        // can synchronize with. To do that we must write `NOTIFIED` even if
+        // `state` is already `NOTIFIED`. That is why this must be a swap
+        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+        // on failure.
+        match self.state.swap(NOTIFIED, SeqCst) {
+            EMPTY => return,    // no one was waiting
+            NOTIFIED => return, // already unparked
+            PARKED => {}        // gotta go wake someone up
+            _ => panic!("inconsistent state in unpark"),
+        }
+
+        // There is a period between when the parked thread sets `state` to
+        // `PARKED` (or last checked `state` in the case of a spurious wake
+        // up) and when it actually waits on `cvar`. If we were to notify
+        // during this period it would be ignored and then when the parked
+        // thread went to sleep it would never wake up. Fortunately, it has
+        // `lock` locked at this stage so we can acquire `lock` to wait until
+        // it is ready to receive the notification.
+        //
+        // Releasing `lock` before the call to `notify_one` means that when the
+        // parked thread wakes it doesn't get woken only to have to wait for us
+        // to release `lock`.
+        drop(self.lock.lock().unwrap());
+        self.cvar.notify_one()
+    }
+}
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
new file mode 100644
index 0000000..5e75ac6
--- /dev/null
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -0,0 +1,13 @@
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "linux",
+        target_os = "android",
+        all(target_arch = "wasm32", target_feature = "atomics"),
+    ))] {
+        mod futex;
+        pub use futex::Parker;
+    } else {
+        mod generic;
+        pub use generic::Parker;
+    }
+}
diff --git a/library/std/src/thread/available_concurrency.rs b/library/std/src/thread/available_concurrency.rs
new file mode 100644
index 0000000..4e805e4
--- /dev/null
+++ b/library/std/src/thread/available_concurrency.rs
@@ -0,0 +1,157 @@
+use crate::io;
+use crate::num::NonZeroUsize;
+
+/// Returns the number of hardware threads available to the program.
+///
+/// This value should be considered only a hint.
+///
+/// # Platform-specific behavior
+///
+/// If interpreted as the number of actual hardware threads, it may undercount on
+/// Windows systems with more than 64 hardware threads. If interpreted as the
+/// available concurrency for that process, it may overcount on Windows systems
+/// when limited by a process wide affinity mask or job object limitations, and
+/// it may overcount on Linux systems when limited by a process wide affinity
+/// mask or affected by cgroups limits.
+///
+/// # Errors
+///
+/// This function will return an error in the following situations, but is not
+/// limited to just these cases:
+///
+/// - If the number of hardware threads is not known for the target platform.
+/// - The process lacks permissions to view the number of hardware threads
+///   available.
+///
+/// # Examples
+///
+/// ```
+/// # #![allow(dead_code)]
+/// #![feature(available_concurrency)]
+/// use std::thread;
+///
+/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1);
+/// ```
+#[unstable(feature = "available_concurrency", issue = "74479")]
+pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+    available_concurrency_internal()
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(windows)] {
+        #[allow(nonstandard_style)]
+        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
+            #[repr(C)]
+            struct SYSTEM_INFO {
+                wProcessorArchitecture: u16,
+                wReserved: u16,
+                dwPageSize: u32,
+                lpMinimumApplicationAddress: *mut u8,
+                lpMaximumApplicationAddress: *mut u8,
+                dwActiveProcessorMask: *mut u8,
+                dwNumberOfProcessors: u32,
+                dwProcessorType: u32,
+                dwAllocationGranularity: u32,
+                wProcessorLevel: u16,
+                wProcessorRevision: u16,
+            }
+            extern "system" {
+                fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
+            }
+            let res = unsafe {
+                let mut sysinfo = crate::mem::zeroed();
+                GetSystemInfo(&mut sysinfo);
+                sysinfo.dwNumberOfProcessors as usize
+            };
+            match res {
+                0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
+                cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
+            }
+        }
+    } else if #[cfg(any(
+        target_os = "android",
+        target_os = "cloudabi",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_os = "ios",
+        target_os = "linux",
+        target_os = "macos",
+        target_os = "solaris",
+        target_os = "illumos",
+    ))] {
+        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
+            match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
+                -1 => Err(io::Error::last_os_error()),
+                0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
+                cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
+            }
+        }
+    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
+        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
+            use crate::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = crate::mem::size_of_val(&cpus);
+
+            unsafe {
+                cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+            }
+
+            // Fallback approach in case of errors or no hardware threads.
+            if cpus < 1 {
+                let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+                let res = unsafe {
+                    libc::sysctl(
+                        mib.as_mut_ptr(),
+                        2,
+                        &mut cpus as *mut _ as *mut _,
+                        &mut cpus_size as *mut _ as *mut _,
+                        ptr::null_mut(),
+                        0,
+                    )
+                };
+
+                // Handle errors if any.
+                if res == -1 {
+                    return Err(io::Error::last_os_error());
+                } else if cpus == 0 {
+                    return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
+                }
+            }
+            Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
+        }
+    } else if #[cfg(target_os = "openbsd")] {
+        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
+            use crate::ptr;
+
+            let mut cpus: libc::c_uint = 0;
+            let mut cpus_size = crate::mem::size_of_val(&cpus);
+            let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
+            let res = unsafe {
+                libc::sysctl(
+                    mib.as_mut_ptr(),
+                    2,
+                    &mut cpus as *mut _ as *mut _,
+                    &mut cpus_size as *mut _ as *mut _,
+                    ptr::null_mut(),
+                    0,
+                )
+            };
+
+            // Handle errors if any.
+            if res == -1 {
+                return Err(io::Error::last_os_error());
+            } else if cpus == 0 {
+                return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
+            }
+
+            Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
+        }
+    } else {
+        // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
+        fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
+            Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
+        }
+    }
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 8c353e2..45c10266 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -159,13 +159,12 @@
 use crate::panic;
 use crate::panicking;
 use crate::str;
-use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
-use crate::sync::{Arc, Condvar, Mutex};
+use crate::sync::Arc;
 use crate::sys::thread as imp;
 use crate::sys_common::mutex;
 use crate::sys_common::thread;
 use crate::sys_common::thread_info;
+use crate::sys_common::thread_parker::Parker;
 use crate::sys_common::{AsInner, IntoInner};
 use crate::time::Duration;
 
@@ -176,9 +175,15 @@
 #[macro_use]
 mod local;
 
+#[unstable(feature = "available_concurrency", issue = "74479")]
+mod available_concurrency;
+
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::local::{AccessError, LocalKey};
 
+#[unstable(feature = "available_concurrency", issue = "74479")]
+pub use available_concurrency::available_concurrency;
+
 // The types used by the thread_local! macro to access TLS keys. Note that there
 // are two types, the "OS" type and the "fast" type. The OS thread local key
 // type is accessed via platform-specific API calls and is slow, while the fast
@@ -667,6 +672,8 @@
 ///
 /// [`channel`]: crate::sync::mpsc
 /// [`join`]: JoinHandle::join
+/// [`Condvar`]: crate::sync::Condvar
+/// [`Mutex`]: crate::sync::Mutex
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn yield_now() {
     imp::Thread::yield_now()
@@ -712,6 +719,8 @@
 ///     panic!()
 /// }
 /// ```
+///
+/// [Mutex]: crate::sync::Mutex
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn panicking() -> bool {
@@ -779,11 +788,6 @@
     imp::Thread::sleep(dur)
 }
 
-// constants for park/unpark
-const EMPTY: usize = 0;
-const PARKED: usize = 1;
-const NOTIFIED: usize = 2;
-
 /// Blocks unless or until the current thread's token is made available.
 ///
 /// A call to `park` does not guarantee that the thread will remain parked
@@ -870,45 +874,11 @@
 ///
 /// [`unpark`]: Thread::unpark
 /// [`thread::park_timeout`]: park_timeout
-//
-// The implementation currently uses the trivial strategy of a Mutex+Condvar
-// with wakeup flag, which does not actually allow spurious wakeups. In the
-// future, this will be implemented in a more efficient way, perhaps along the lines of
-//   http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
-// or futuxes, and in either case may allow spurious wakeups.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn park() {
-    let thread = current();
-
-    // If we were previously notified then we consume this notification and
-    // return quickly.
-    if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-        return;
-    }
-
-    // Otherwise we need to coordinate going to sleep
-    let mut m = thread.inner.lock.lock().unwrap();
-    match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-        Ok(_) => {}
-        Err(NOTIFIED) => {
-            // We must read here, even though we know it will be `NOTIFIED`.
-            // This is because `unpark` may have been called again since we read
-            // `NOTIFIED` in the `compare_exchange` above. We must perform an
-            // acquire operation that synchronizes with that `unpark` to observe
-            // any writes it made before the call to unpark. To do that we must
-            // read from the write it made to `state`.
-            let old = thread.inner.state.swap(EMPTY, SeqCst);
-            assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-            return;
-        } // should consume this notification, so prohibit spurious wakeups in next park.
-        Err(_) => panic!("inconsistent park state"),
-    }
-    loop {
-        m = thread.inner.cvar.wait(m).unwrap();
-        match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
-            Ok(_) => return, // got a notification
-            Err(_) => {}     // spurious wakeup, go back to sleep
-        }
+    // SAFETY: park_timeout is called on the parker owned by this thread.
+    unsafe {
+        current().inner.parker.park();
     }
 }
 
@@ -970,35 +940,9 @@
 /// ```
 #[stable(feature = "park_timeout", since = "1.4.0")]
 pub fn park_timeout(dur: Duration) {
-    let thread = current();
-
-    // Like `park` above we have a fast path for an already-notified thread, and
-    // afterwards we start coordinating for a sleep.
-    // return quickly.
-    if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
-        return;
-    }
-    let m = thread.inner.lock.lock().unwrap();
-    match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
-        Ok(_) => {}
-        Err(NOTIFIED) => {
-            // We must read again here, see `park`.
-            let old = thread.inner.state.swap(EMPTY, SeqCst);
-            assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
-            return;
-        } // should consume this notification, so prohibit spurious wakeups in next park.
-        Err(_) => panic!("inconsistent park_timeout state"),
-    }
-
-    // Wait with a timeout, and if we spuriously wake up or otherwise wake up
-    // from a notification we just want to unconditionally set the state back to
-    // empty, either consuming a notification or un-flagging ourselves as
-    // parked.
-    let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap();
-    match thread.inner.state.swap(EMPTY, SeqCst) {
-        NOTIFIED => {} // got a notification, hurray!
-        PARKED => {}   // no notification, alas
-        n => panic!("inconsistent park_timeout state: {}", n),
+    // SAFETY: park_timeout is called on the parker owned by this thread.
+    unsafe {
+        current().inner.parker.park_timeout(dur);
     }
 }
 
@@ -1034,9 +978,8 @@
 impl ThreadId {
     // Generate a new unique thread ID.
     fn new() -> ThreadId {
-        // We never call `GUARD.init()`, so it is UB to attempt to
-        // acquire this mutex reentrantly!
-        static GUARD: mutex::Mutex = mutex::Mutex::new();
+        // It is UB to attempt to acquire this mutex reentrantly!
+        static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
         static mut COUNTER: u64 = 1;
 
         unsafe {
@@ -1077,11 +1020,7 @@
 struct Inner {
     name: Option<CString>, // Guaranteed to be UTF-8
     id: ThreadId,
-
-    // state for thread park/unpark
-    state: AtomicUsize,
-    lock: Mutex<()>,
-    cvar: Condvar,
+    parker: Parker,
 }
 
 #[derive(Clone)]
@@ -1115,13 +1054,7 @@
         let cname =
             name.map(|n| CString::new(n).expect("thread name may not contain interior null bytes"));
         Thread {
-            inner: Arc::new(Inner {
-                name: cname,
-                id: ThreadId::new(),
-                state: AtomicUsize::new(EMPTY),
-                lock: Mutex::new(()),
-                cvar: Condvar::new(),
-            }),
+            inner: Arc::new(Inner { name: cname, id: ThreadId::new(), parker: Parker::new() }),
         }
     }
 
@@ -1156,33 +1089,9 @@
     /// parked_thread.join().unwrap();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
     pub fn unpark(&self) {
-        // To ensure the unparked thread will observe any writes we made
-        // before this call, we must perform a release operation that `park`
-        // can synchronize with. To do that we must write `NOTIFIED` even if
-        // `state` is already `NOTIFIED`. That is why this must be a swap
-        // rather than a compare-and-swap that returns if it reads `NOTIFIED`
-        // on failure.
-        match self.inner.state.swap(NOTIFIED, SeqCst) {
-            EMPTY => return,    // no one was waiting
-            NOTIFIED => return, // already unparked
-            PARKED => {}        // gotta go wake someone up
-            _ => panic!("inconsistent state in unpark"),
-        }
-
-        // There is a period between when the parked thread sets `state` to
-        // `PARKED` (or last checked `state` in the case of a spurious wake
-        // up) and when it actually waits on `cvar`. If we were to notify
-        // during this period it would be ignored and then when the parked
-        // thread went to sleep it would never wake up. Fortunately, it has
-        // `lock` locked at this stage so we can acquire `lock` to wait until
-        // it is ready to receive the notification.
-        //
-        // Releasing `lock` before the call to `notify_one` means that when the
-        // parked thread wakes it doesn't get woken only to have to wait for us
-        // to release `lock`.
-        drop(self.inner.lock.lock().unwrap());
-        self.inner.cvar.notify_one()
+        self.inner.parker.unpark();
     }
 
     /// Gets the thread's unique identifier.
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 18e38c6..64d7898 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -20,7 +20,7 @@
 use crate::fmt;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::sys::time;
-use crate::sys_common::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 use crate::sys_common::FromInner;
 
 #[stable(feature = "time", since = "1.3.0")]
@@ -100,6 +100,11 @@
 /// [clock_time_get (Monotonic Clock)]: https://nuxi.nl/cloudabi/#clock_time_get
 ///
 /// **Disclaimer:** These system calls might change over time.
+///
+/// > Note: mathematical operations like [`add`] may panic if the underlying
+/// > structure cannot represent the new point in time.
+///
+/// [`add`]: Instant::add
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct Instant(time::Instant);
@@ -174,6 +179,11 @@
 /// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime
 ///
 /// **Disclaimer:** These system calls might change over time.
+///
+/// > Note: mathematical operations like [`add`] may panic if the underlying
+/// > structure cannot represent the new point in time.
+///
+/// [`add`]: SystemTime::add
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct SystemTime(time::SystemTime);
@@ -243,7 +253,7 @@
             return Instant(os_now);
         }
 
-        static LOCK: Mutex = Mutex::new();
+        static LOCK: StaticMutex = StaticMutex::new();
         static mut LAST_NOW: time::Instant = time::Instant::zero();
         unsafe {
             let _lock = LOCK.lock();
diff --git a/library/stdarch b/library/stdarch
index b422b01..3c36643 160000
--- a/library/stdarch
+++ b/library/stdarch
@@ -1 +1 @@
-Subproject commit b422b0180f7c3327375a63a3e6660e432b9ec75d
+Subproject commit 3c3664355ef46e788b53080e521d6542fbddfd84
diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml
index 7b76dc8..e44c781 100644
--- a/library/test/Cargo.toml
+++ b/library/test/Cargo.toml
@@ -25,6 +25,7 @@
 default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
 backtrace = ["std/backtrace"]
 compiler-builtins-c = ["std/compiler-builtins-c"]
+compiler-builtins-mem = ["std/compiler-builtins-mem"]
 llvm-libunwind = ["std/llvm-libunwind"]
 panic-unwind = ["std/panic_unwind"]
 panic_immediate_abort = ["std/panic_immediate_abort"]
diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs
index a03cf9d..10546de 100644
--- a/library/test/src/bench.rs
+++ b/library/test/src/bench.rs
@@ -159,7 +159,7 @@
             return summ5;
         }
 
-        total_run = total_run + loop_run;
+        total_run += loop_run;
         // Longest we ever run for is 3s.
         if total_run > Duration::from_secs(3) {
             return summ5;
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 9ebc991..4dc4162 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -39,9 +39,12 @@
         stdout: Option<Cow<'_, str>>,
         extra: Option<&str>,
     ) -> io::Result<()> {
+        // A doc test's name includes a filename which must be escaped for correct json.
         self.write_message(&*format!(
             r#"{{ "type": "{}", "name": "{}", "event": "{}""#,
-            ty, name, evt
+            ty,
+            EscapedString(name),
+            evt
         ))?;
         if let Some(exec_time) = exec_time {
             self.write_message(&*format!(r#", "exec_time": "{}""#, exec_time))?;
@@ -67,7 +70,7 @@
     fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
         self.writeln_message(&*format!(
             r#"{{ "type": "test", "event": "started", "name": "{}" }}"#,
-            desc.name
+            EscapedString(desc.name.as_slice())
         ))
     }
 
@@ -140,7 +143,10 @@
                      \"name\": \"{}\", \
                      \"median\": {}, \
                      \"deviation\": {}{} }}",
-                    desc.name, median, deviation, mbps
+                    EscapedString(desc.name.as_slice()),
+                    median,
+                    deviation,
+                    mbps
                 );
 
                 self.writeln_message(&*line)
@@ -151,7 +157,7 @@
     fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
         self.writeln_message(&*format!(
             r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#,
-            desc.name
+            EscapedString(desc.name.as_slice())
         ))
     }
 
@@ -182,8 +188,8 @@
 /// Base code taken form `libserialize::json::escape_str`
 struct EscapedString<S: AsRef<str>>(S);
 
-impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+impl<S: AsRef<str>> std::fmt::Display for EscapedString<S> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         let mut start = 0;
 
         for (i, byte) in self.0.as_ref().bytes().enumerate() {
diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs
index 4a93e08..8c90b57 100644
--- a/library/test/src/formatters/pretty.rs
+++ b/library/test/src/formatters/pretty.rs
@@ -139,7 +139,7 @@
                 stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 stdouts.push_str(&output);
-                stdouts.push_str("\n");
+                stdouts.push('\n');
             }
         }
         if !stdouts.is_empty() {
diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs
index 5a264d2..1ae7846 100644
--- a/library/test/src/formatters/terse.rs
+++ b/library/test/src/formatters/terse.rs
@@ -114,7 +114,7 @@
                 stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 stdouts.push_str(&output);
-                stdouts.push_str("\n");
+                stdouts.push('\n');
             }
         }
         if !stdouts.is_empty() {
@@ -140,7 +140,7 @@
                 fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 fail_out.push_str(&output);
-                fail_out.push_str("\n");
+                fail_out.push('\n');
             }
         }
         if !fail_out.is_empty() {
diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs
index 7ca27bf..7e9bd50 100644
--- a/library/test/src/helpers/concurrency.rs
+++ b/library/test/src/helpers/concurrency.rs
@@ -1,6 +1,7 @@
 //! Helper module which helps to determine amount of threads to be used
 //! during tests execution.
 use std::env;
+use std::thread;
 
 #[allow(deprecated)]
 pub fn get_concurrency() -> usize {
@@ -12,106 +13,6 @@
                 _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s),
             }
         }
-        Err(..) => num_cpus(),
-    }
-}
-
-cfg_if::cfg_if! {
-    if #[cfg(windows)] {
-        #[allow(nonstandard_style)]
-        fn num_cpus() -> usize {
-            #[repr(C)]
-            struct SYSTEM_INFO {
-                wProcessorArchitecture: u16,
-                wReserved: u16,
-                dwPageSize: u32,
-                lpMinimumApplicationAddress: *mut u8,
-                lpMaximumApplicationAddress: *mut u8,
-                dwActiveProcessorMask: *mut u8,
-                dwNumberOfProcessors: u32,
-                dwProcessorType: u32,
-                dwAllocationGranularity: u32,
-                wProcessorLevel: u16,
-                wProcessorRevision: u16,
-            }
-            extern "system" {
-                fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
-            }
-            unsafe {
-                let mut sysinfo = std::mem::zeroed();
-                GetSystemInfo(&mut sysinfo);
-                sysinfo.dwNumberOfProcessors as usize
-            }
-        }
-    } else if #[cfg(any(
-        target_os = "android",
-        target_os = "cloudabi",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "solaris",
-        target_os = "illumos",
-    ))] {
-        fn num_cpus() -> usize {
-            unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
-        }
-    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
-        fn num_cpus() -> usize {
-            use std::ptr;
-
-            let mut cpus: libc::c_uint = 0;
-            let mut cpus_size = std::mem::size_of_val(&cpus);
-
-            unsafe {
-                cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
-            }
-            if cpus < 1 {
-                let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-                unsafe {
-                    libc::sysctl(
-                        mib.as_mut_ptr(),
-                        2,
-                        &mut cpus as *mut _ as *mut _,
-                        &mut cpus_size as *mut _ as *mut _,
-                        ptr::null_mut(),
-                        0,
-                    );
-                }
-                if cpus < 1 {
-                    cpus = 1;
-                }
-            }
-            cpus as usize
-        }
-    } else if #[cfg(target_os = "openbsd")] {
-        fn num_cpus() -> usize {
-            use std::ptr;
-
-            let mut cpus: libc::c_uint = 0;
-            let mut cpus_size = std::mem::size_of_val(&cpus);
-            let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-
-            unsafe {
-                libc::sysctl(
-                    mib.as_mut_ptr(),
-                    2,
-                    &mut cpus as *mut _ as *mut _,
-                    &mut cpus_size as *mut _ as *mut _,
-                    ptr::null_mut(),
-                    0,
-                );
-            }
-            if cpus < 1 {
-                cpus = 1;
-            }
-            cpus as usize
-        }
-    } else {
-        // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
-        fn num_cpus() -> usize {
-            1
-        }
+        Err(..) => thread::available_concurrency().map(|n| n.get()).unwrap_or(1),
     }
 }
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index caea4b1..9c5bb89 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -24,6 +24,7 @@
 #![feature(rustc_private)]
 #![feature(nll)]
 #![feature(bool_to_option)]
+#![feature(available_concurrency)]
 #![feature(set_stdio)]
 #![feature(panic_unwind)]
 #![feature(staged_api)]
@@ -237,11 +238,9 @@
     let event = TestEvent::TeFiltered(filtered_descs);
     notify_about_test_event(event)?;
 
-    let (filtered_tests, filtered_benchs): (Vec<_>, _) =
-        filtered_tests.into_iter().partition(|e| match e.testfn {
-            StaticTestFn(_) | DynTestFn(_) => true,
-            _ => false,
-        });
+    let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests
+        .into_iter()
+        .partition(|e| matches!(e.testfn, StaticTestFn(_) | DynTestFn(_)));
 
     let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
 
diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs
index 1a2cb89..53f3889 100644
--- a/library/test/src/stats.rs
+++ b/library/test/src/stats.rs
@@ -199,7 +199,7 @@
             let mut v: f64 = 0.0;
             for s in self {
                 let x = *s - mean;
-                v = v + x * x;
+                v += x * x;
             }
             // N.B., this is _supposed to be_ len-1, not len. If you
             // change it back to len, you will be calculating a
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index 8e2db21..7138d0c 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -14,7 +14,7 @@
 
 [dependencies]
 core = { path = "../core" }
-libc = { version = "0.2.51", features = ['rustc-dep-of-std'], default-features = false }
+libc = { version = "0.2.79", features = ['rustc-dep-of-std'], default-features = false }
 compiler_builtins = "0.1.0"
 cfg-if = "0.1.8"
 
diff --git a/library/unwind/build.rs b/library/unwind/build.rs
index ab09a6e..24bcd40 100644
--- a/library/unwind/build.rs
+++ b/library/unwind/build.rs
@@ -12,11 +12,9 @@
     } else if target.contains("x86_64-fortanix-unknown-sgx") {
         llvm_libunwind::compile();
     } else if target.contains("linux") {
+        // linking for Linux is handled in lib.rs
         if target.contains("musl") {
-            // linking for musl is handled in lib.rs
             llvm_libunwind::compile();
-        } else if !target.contains("android") {
-            println!("cargo:rustc-link-lib=gcc_s");
         }
     } else if target.contains("freebsd") {
         println!("cargo:rustc-link-lib=gcc_s");
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 20a2ca9..e7fa37b 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -42,6 +42,13 @@
 #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
 extern "C" {}
 
+// When building with crt-static, we get `gcc_eh` from the `libc` crate, since
+// glibc needs it, and needs it listed later on the linker command line. We
+// don't want to duplicate it here.
+#[cfg(all(target_os = "linux", target_env = "gnu", not(feature = "llvm-libunwind")))]
+#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
+extern "C" {}
+
 #[cfg(target_os = "redox")]
 #[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
 #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index dcf4fcd..ff1d82f 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -51,7 +51,7 @@
 #[cfg(target_arch = "s390x")]
 pub const unwinder_private_data_size: usize = 2;
 
-#[cfg(target_arch = "sparc64")]
+#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
 pub const unwinder_private_data_size: usize = 2;
 
 #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
@@ -89,7 +89,7 @@
 }
 
 cfg_if::cfg_if! {
-if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))] {
+if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] {
     // Not ARM EHABI
     #[repr(C)]
     #[derive(Copy, Clone, PartialEq)]
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index dfb39c5..7bb4e50 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -6,22 +6,33 @@
 
 ## [Non-breaking changes since the last major version]
 
+- `x.py check` needs opt-in to check tests (--all-targets) [#77473](https://github.com/rust-lang/rust/pull/77473)
+- The default bootstrap profiles are now located at `bootstrap/defaults/config.$PROFILE.toml` (previously they were located at `bootstrap/defaults/config.toml.$PROFILE`) [#77558](https://github.com/rust-lang/rust/pull/77558)
+
+
+## [Version 2] - 2020-09-25
+
+- `host` now defaults to the value of `build` in all cases
+  + Previously `host` defaulted to an empty list when `target` was overridden, and to `build` otherwise
+
+### Non-breaking changes
+
 - Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631)
 - Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626)
-- Optionally, download LLVM from CI on Linux and NixOS
+- Optionally, download LLVM from CI on Linux and NixOS. This can be enabled with `download-ci-llvm = true` under `[llvm]`.
   + [#76439](https://github.com/rust-lang/rust/pull/76349)
   + [#76667](https://github.com/rust-lang/rust/pull/76667)
   + [#76708](https://github.com/rust-lang/rust/pull/76708)
 - Distribute rustc sources as part of `rustc-dev` [#76856](https://github.com/rust-lang/rust/pull/76856)
-- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625)
-- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588)
+- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625). This can be enabled with `build-stage = N`, `doc-stage = N`, etc.
+- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588). Previously, `debug-logging` could only be set with `debug-assertions`, slowing down the compiler more than necessary.
 - Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628)
 - Add `--keep-stage-std`, which behaves like `keep-stage` but allows the stage
   0 compiler artifacts (i.e., stage1/bin/rustc) to be rebuilt if changed
   [#77120](https://github.com/rust-lang/rust/pull/77120).
 
 
-## [Version 0] - 2020-09-11
+## [Version 1] - 2020-09-11
 
 This is the first changelog entry, and it does not attempt to be an exhaustive list of features in x.py.
 Instead, this documents the changes to bootstrap in the past 2 months.
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index bc8bae1..84ed944 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -93,12 +93,12 @@
 installations, and is primarily useful for CI. Prefer to customize behavior
 using `config.toml`.
 
-Finally, rustbuild makes use of the [gcc-rs crate] which has [its own
+Finally, rustbuild makes use of the [cc-rs crate] which has [its own
 method][env-vars] of configuring C compilers and C flags via environment
 variables.
 
-[gcc-rs crate]: https://github.com/alexcrichton/gcc-rs
-[env-vars]: https://github.com/alexcrichton/gcc-rs#external-configuration-via-environment-variables
+[cc-rs crate]: https://github.com/alexcrichton/cc-rs
+[env-vars]: https://github.com/alexcrichton/cc-rs#external-configuration-via-environment-variables
 
 ## Build stages
 
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs
index 637083e..07e582d 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/bin/main.rs
@@ -7,13 +7,15 @@
 
 use std::env;
 
-use bootstrap::{Build, Config, Subcommand};
+use bootstrap::{Build, Config, Subcommand, VERSION};
 
 fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
     let config = Config::parse(&args);
 
-    let changelog_suggestion = check_version(&config);
+    // check_version warnings are not printed during setup
+    let changelog_suggestion =
+        if matches!(config.cmd, Subcommand::Setup {..}) { None } else { check_version(&config) };
 
     // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
     // changelog warning, not the `x.py setup` message.
@@ -40,8 +42,6 @@
 }
 
 fn check_version(config: &Config) -> Option<String> {
-    const VERSION: usize = 1;
-
     let mut msg = String::new();
 
     let suggestion = if let Some(seen) = config.changelog_seen {
diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs
index cb58eb8..cba17c8 100644
--- a/src/bootstrap/bin/rustdoc.rs
+++ b/src/bootstrap/bin/rustdoc.rs
@@ -11,7 +11,6 @@
     let args = env::args_os().skip(1).collect::<Vec<_>>();
     let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
     let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set");
-    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
     let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
 
     use std::str::FromStr;
@@ -24,14 +23,8 @@
     let mut dylib_path = bootstrap::util::dylib_path();
     dylib_path.insert(0, PathBuf::from(libdir.clone()));
 
-    //FIXME(misdreavus): once stdsimd uses cfg(doc) instead of cfg(dox), remove the `--cfg dox`
-    //arguments here
     let mut cmd = Command::new(rustdoc);
     cmd.args(&args)
-        .arg("--cfg")
-        .arg(format!("stage{}", stage))
-        .arg("--cfg")
-        .arg("dox")
         .arg("--sysroot")
         .arg(&sysroot)
         .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5c9184f..8fe0d25 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -435,7 +435,9 @@
             llvm_sha = subprocess.check_output([
                 "git", "log", "--author=bors", "--format=%H", "-n1",
                 "-m", "--first-parent",
-                "--", "src/llvm-project"
+                "--",
+                "src/llvm-project",
+                "src/bootstrap/download-ci-llvm-stamp",
             ]).decode(sys.getdefaultencoding()).strip()
             llvm_assertions = self.get_toml('assertions', 'llvm') == 'true'
             if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
@@ -447,7 +449,8 @@
 
     def downloading_llvm(self):
         opt = self.get_toml('download-ci-llvm', 'llvm')
-        return opt == "true"
+        return opt == "true" \
+            or (opt == "if-available" and self.build == "x86_64-unknown-linux-gnu")
 
     def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None):
         if date is None:
@@ -890,10 +893,15 @@
         ).decode(default_encoding).splitlines()]
         filtered_submodules = []
         submodules_names = []
+        llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git"))
         for module in submodules:
             if module.endswith("llvm-project"):
-                if self.get_toml('llvm-config') or self.get_toml('download-ci-llvm') == 'true':
-                    if self.get_toml('lld') != 'true':
+                # Don't sync the llvm-project submodule either if an external LLVM
+                # was provided, or if we are downloading LLVM. Also, if the
+                # submodule has been initialized already, sync it anyways so that
+                # it doesn't mess up contributor pull requests.
+                if self.get_toml('llvm-config') or self.downloading_llvm():
+                    if self.get_toml('lld') != 'true' and not llvm_checked_out:
                         continue
             check = self.check_submodule(module, slow_submodules)
             filtered_submodules.append((module, check))
@@ -1003,6 +1011,16 @@
         with open(toml_path) as config:
             build.config_toml = config.read()
 
+    profile = build.get_toml('profile')
+    if profile is not None:
+        include_file = 'config.{}.toml'.format(profile)
+        include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults')
+        include_path = os.path.join(include_dir, include_file)
+        # HACK: This works because `build.get_toml()` returns the first match it finds for a
+        # specific key, so appending our defaults at the end allows the user to override them
+        with open(include_path) as included_toml:
+            build.config_toml += os.linesep + included_toml.read()
+
     config_verbose = build.get_toml('verbose', 'build')
     if config_verbose is not None:
         build.verbose = max(build.verbose, int(config_verbose))
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 4aaaeb8..707c1ff 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -172,15 +172,7 @@
         }
 
         // Determine the targets participating in this rule.
-        let targets = if self.only_hosts {
-            if builder.config.skip_only_host_steps {
-                return; // don't run anything
-            } else {
-                &builder.hosts
-            }
-        } else {
-            &builder.targets
-        };
+        let targets = if self.only_hosts { &builder.hosts } else { &builder.targets };
 
         for target in targets {
             let run = RunConfig { builder, path: pathset.path(builder), target: *target };
@@ -201,37 +193,37 @@
             );
         }
 
-        if paths.is_empty() {
-            for (desc, should_run) in v.iter().zip(should_runs) {
+        if paths.is_empty() || builder.config.include_default_paths {
+            for (desc, should_run) in v.iter().zip(&should_runs) {
                 if desc.default && should_run.is_really_default {
                     for pathset in &should_run.paths {
                         desc.maybe_run(builder, pathset);
                     }
                 }
             }
-        } else {
-            for path in paths {
-                // strip CurDir prefix if present
-                let path = match path.strip_prefix(".") {
-                    Ok(p) => p,
-                    Err(_) => path,
-                };
+        }
 
-                let mut attempted_run = false;
-                for (desc, should_run) in v.iter().zip(&should_runs) {
-                    if let Some(suite) = should_run.is_suite_path(path) {
-                        attempted_run = true;
-                        desc.maybe_run(builder, suite);
-                    } else if let Some(pathset) = should_run.pathset_for_path(path) {
-                        attempted_run = true;
-                        desc.maybe_run(builder, pathset);
-                    }
-                }
+        for path in paths {
+            // strip CurDir prefix if present
+            let path = match path.strip_prefix(".") {
+                Ok(p) => p,
+                Err(_) => path,
+            };
 
-                if !attempted_run {
-                    panic!("error: no rules matched {}", path.display());
+            let mut attempted_run = false;
+            for (desc, should_run) in v.iter().zip(&should_runs) {
+                if let Some(suite) = should_run.is_suite_path(path) {
+                    attempted_run = true;
+                    desc.maybe_run(builder, suite);
+                } else if let Some(pathset) = should_run.pathset_for_path(path) {
+                    attempted_run = true;
+                    desc.maybe_run(builder, pathset);
                 }
             }
+
+            if !attempted_run {
+                panic!("error: no rules matched {}", path.display());
+            }
         }
     }
 }
@@ -470,6 +462,7 @@
                 dist::LlvmTools,
                 dist::RustDev,
                 dist::Extended,
+                dist::BuildManifest,
                 dist::HashSign
             ),
             Kind::Install => describe!(
@@ -485,7 +478,7 @@
                 install::Src,
                 install::Rustc
             ),
-            Kind::Run => describe!(run::ExpandYamlAnchors,),
+            Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest),
         }
     }
 
@@ -540,7 +533,7 @@
     pub fn new(build: &Build) -> Builder<'_> {
         let (kind, paths) = match build.config.cmd {
             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
-            Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
+            Subcommand::Check { ref paths, all_targets: _ } => (Kind::Check, &paths[..]),
             Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]),
             Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
             Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 4a9082d..a367aa5 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -6,7 +6,6 @@
     let mut config = Config::parse(&[cmd.to_owned()]);
     // don't save toolstates
     config.save_toolstates = None;
-    config.skip_only_host_steps = false;
     config.dry_run = true;
     config.ninja_in_file = false;
     // try to avoid spurious failures in dist where we create/delete each others file
@@ -20,16 +19,8 @@
     t!(fs::create_dir_all(&dir));
     config.out = dir;
     config.build = TargetSelection::from_user("A");
-    config.hosts = vec![config.build]
-        .into_iter()
-        .chain(host.iter().map(|s| TargetSelection::from_user(s)))
-        .collect::<Vec<_>>();
-    config.targets = config
-        .hosts
-        .clone()
-        .into_iter()
-        .chain(target.iter().map(|s| TargetSelection::from_user(s)))
-        .collect::<Vec<_>>();
+    config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect();
+    config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect();
     config
 }
 
@@ -45,7 +36,7 @@
 
     #[test]
     fn build_default() {
-        let build = Build::new(configure("build", &[], &[]));
+        let build = Build::new(configure("build", &["A"], &["A"]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
 
@@ -73,7 +64,7 @@
 
     #[test]
     fn build_stage_0() {
-        let config = Config { stage: 0, ..configure("build", &[], &[]) };
+        let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) };
         let build = Build::new(config);
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
@@ -95,7 +86,7 @@
 
     #[test]
     fn build_cross_compile() {
-        let config = Config { stage: 1, ..configure("build", &["B"], &["B"]) };
+        let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) };
         let build = Build::new(config);
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
@@ -143,7 +134,7 @@
 
     #[test]
     fn doc_default() {
-        let mut config = configure("doc", &[], &[]);
+        let mut config = configure("doc", &["A"], &["A"]);
         config.compiler_docs = true;
         config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
         let build = Build::new(config);
@@ -182,7 +173,7 @@
 
     #[test]
     fn dist_baseline() {
-        let build = Build::new(configure(&[], &[]));
+        let build = Build::new(configure(&["A"], &["A"]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
@@ -208,7 +199,7 @@
 
     #[test]
     fn dist_with_targets() {
-        let build = Build::new(configure(&[], &["B"]));
+        let build = Build::new(configure(&["A"], &["A", "B"]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
@@ -239,7 +230,7 @@
 
     #[test]
     fn dist_with_hosts() {
-        let build = Build::new(configure(&["B"], &[]));
+        let build = Build::new(configure(&["A", "B"], &["A", "B"]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
@@ -285,7 +276,7 @@
     fn dist_only_cross_host() {
         let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
-        let mut build = Build::new(configure(&["B"], &[]));
+        let mut build = Build::new(configure(&["A", "B"], &["A", "B"]));
         build.config.docs = false;
         build.config.extended = true;
         build.hosts = vec![b];
@@ -307,7 +298,7 @@
 
     #[test]
     fn dist_with_targets_and_hosts() {
-        let build = Build::new(configure(&["B"], &["C"]));
+        let build = Build::new(configure(&["A", "B"], &["A", "B", "C"]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
@@ -342,40 +333,26 @@
     }
 
     #[test]
-    fn dist_with_target_flag() {
-        let mut config = configure(&["B"], &["C"]);
-        config.skip_only_host_steps = true; // as-if --target=C was passed
+    fn dist_with_empty_host() {
+        let config = configure(&[], &["C"]);
         let build = Build::new(config);
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
         let a = TargetSelection::from_user("A");
-        let b = TargetSelection::from_user("B");
         let c = TargetSelection::from_user("C");
 
-        assert_eq!(
-            first(builder.cache.all::<dist::Docs>()),
-            &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
-        );
-        assert_eq!(
-            first(builder.cache.all::<dist::Mingw>()),
-            &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
-        );
-        assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
+        assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: c },]);
+        assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: c },]);
         assert_eq!(
             first(builder.cache.all::<dist::Std>()),
-            &[
-                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-                dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
-            ]
+            &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },]
         );
-        assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
     }
 
     #[test]
     fn dist_with_same_targets_and_hosts() {
-        let build = Build::new(configure(&["B"], &["B"]));
+        let build = Build::new(configure(&["A", "B"], &["A", "B"]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
 
@@ -428,7 +405,7 @@
 
     #[test]
     fn build_all() {
-        let build = Build::new(configure(&["B"], &["C"]));
+        let build = Build::new(configure(&["A", "B"], &["A", "B", "C"]));
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(
             &Builder::get_step_descriptions(Kind::Build),
@@ -464,15 +441,13 @@
     }
 
     #[test]
-    fn build_with_target_flag() {
-        let mut config = configure(&["B"], &["C"]);
-        config.skip_only_host_steps = true;
+    fn build_with_empty_host() {
+        let config = configure(&[], &["C"]);
         let build = Build::new(config);
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
 
         let a = TargetSelection::from_user("A");
-        let b = TargetSelection::from_user("B");
         let c = TargetSelection::from_user("C");
 
         assert_eq!(
@@ -480,9 +455,6 @@
             &[
                 compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
                 compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
                 compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
             ]
         );
@@ -505,7 +477,7 @@
 
     #[test]
     fn test_with_no_doc_stage0() {
-        let mut config = configure(&[], &[]);
+        let mut config = configure(&["A"], &["A"]);
         config.stage = 0;
         config.cmd = Subcommand::Test {
             paths: vec!["library/std".into()],
@@ -545,7 +517,7 @@
 
     #[test]
     fn test_exclude() {
-        let mut config = configure(&[], &[]);
+        let mut config = configure(&["A"], &["A"]);
         config.exclude = vec!["src/tools/tidy".into()];
         config.cmd = Subcommand::Test {
             paths: Vec::new(),
@@ -572,7 +544,7 @@
 
     #[test]
     fn doc_ci() {
-        let mut config = configure(&[], &[]);
+        let mut config = configure(&["A"], &["A"]);
         config.compiler_docs = true;
         config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
         let build = Build::new(config);
@@ -601,7 +573,7 @@
     #[test]
     fn test_docs() {
         // Behavior of `x.py test` doing various documentation tests.
-        let mut config = configure(&[], &[]);
+        let mut config = configure(&["A"], &["A"]);
         config.cmd = Subcommand::Test {
             paths: vec![],
             test_args: vec![],
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index ead0bd0..3716311 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1,9 +1,12 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
-use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, std_cargo};
 use crate::config::TargetSelection;
 use crate::tool::{prepare_tool_cargo, SourceType};
+use crate::{
+    builder::{Builder, Kind, RunConfig, ShouldRun, Step},
+    Subcommand,
+};
 use crate::{Compiler, Mode};
 use std::path::PathBuf;
 
@@ -74,35 +77,37 @@
         //
         // Currently only the "libtest" tree of crates does this.
 
-        let mut cargo = builder.cargo(
-            compiler,
-            Mode::Std,
-            SourceType::InTree,
-            target,
-            cargo_subcommand(builder.kind),
-        );
-        std_cargo(builder, target, compiler.stage, &mut cargo);
-        cargo.arg("--all-targets");
+        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
+            let mut cargo = builder.cargo(
+                compiler,
+                Mode::Std,
+                SourceType::InTree,
+                target,
+                cargo_subcommand(builder.kind),
+            );
+            std_cargo(builder, target, compiler.stage, &mut cargo);
+            cargo.arg("--all-targets");
 
-        // Explicitly pass -p for all dependencies krates -- this will force cargo
-        // to also check the tests/benches/examples for these crates, rather
-        // than just the leaf crate.
-        for krate in builder.in_tree_crates("test") {
-            cargo.arg("-p").arg(krate.name);
+            // Explicitly pass -p for all dependencies krates -- this will force cargo
+            // to also check the tests/benches/examples for these crates, rather
+            // than just the leaf crate.
+            for krate in builder.in_tree_crates("test") {
+                cargo.arg("-p").arg(krate.name);
+            }
+
+            builder.info(&format!(
+                "Checking std test/bench/example targets ({} -> {})",
+                &compiler.host, target
+            ));
+            run_cargo(
+                builder,
+                cargo,
+                args(builder.kind),
+                &libstd_test_stamp(builder, compiler, target),
+                vec![],
+                true,
+            );
         }
-
-        builder.info(&format!(
-            "Checking std test/bench/example targets ({} -> {})",
-            &compiler.host, target
-        ));
-        run_cargo(
-            builder,
-            cargo,
-            args(builder.kind),
-            &libstd_test_stamp(builder, compiler, target),
-            vec![],
-            true,
-        );
     }
 }
 
@@ -143,7 +148,9 @@
             cargo_subcommand(builder.kind),
         );
         rustc_cargo(builder, &mut cargo, target);
-        cargo.arg("--all-targets");
+        if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
+            cargo.arg("--all-targets");
+        }
 
         // Explicitly pass -p for all compiler krates -- this will force cargo
         // to also check the tests/benches/examples for these crates, rather
@@ -205,7 +212,9 @@
                     &[],
                 );
 
-                cargo.arg("--all-targets");
+                if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
+                    cargo.arg("--all-targets");
+                }
 
                 builder.info(&format!(
                     "Checking {} artifacts ({} -> {})",
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 40bf6c4..5215ab3 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -234,14 +234,14 @@
         // Note that `libprofiler_builtins/build.rs` also computes this so if
         // you're changing something here please also change that.
         cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
-        " compiler-builtins-c".to_string()
+        " compiler-builtins-c"
     } else {
-        String::new()
+        ""
     };
 
     if builder.no_std(target) == Some(true) {
         let mut features = "compiler-builtins-mem".to_string();
-        features.push_str(&compiler_builtins_c_feature);
+        features.push_str(compiler_builtins_c_feature);
 
         // for no-std targets we only compile a few no_std crates
         cargo
@@ -249,10 +249,10 @@
             .arg("--manifest-path")
             .arg(builder.src.join("library/alloc/Cargo.toml"))
             .arg("--features")
-            .arg("compiler-builtins-mem compiler-builtins-c");
+            .arg(features);
     } else {
         let mut features = builder.std_features();
-        features.push_str(&compiler_builtins_c_feature);
+        features.push_str(compiler_builtins_c_feature);
 
         cargo
             .arg("--features")
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index b14746d..3c1249f 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -61,13 +61,12 @@
     pub profiler: bool,
     pub ignore_git: bool,
     pub exclude: Vec<PathBuf>,
+    pub include_default_paths: bool,
     pub rustc_error_format: Option<String>,
     pub json_output: bool,
     pub test_compare_mode: bool,
     pub llvm_libunwind: bool,
 
-    pub skip_only_host_steps: bool,
-
     pub on_fail: Option<String>,
     pub stage: u32,
     pub keep_stage: Vec<u32>,
@@ -392,7 +391,7 @@
     use_libcxx: Option<bool>,
     use_linker: Option<String>,
     allow_old_toolchain: Option<bool>,
-    download_ci_llvm: Option<bool>,
+    download_ci_llvm: Option<StringOrBool>,
 }
 
 #[derive(Deserialize, Default, Clone, Merge)]
@@ -515,7 +514,6 @@
         config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
         config.deny_warnings = true;
         config.missing_tools = false;
-        config.config = PathBuf::from("config.toml");
 
         // set by bootstrap.py
         config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
@@ -535,6 +533,7 @@
 
         let mut config = Config::default_opts();
         config.exclude = flags.exclude;
+        config.include_default_paths = flags.include_default_paths;
         config.rustc_error_format = flags.rustc_error_format;
         config.json_output = flags.json_output;
         config.on_fail = flags.on_fail;
@@ -558,10 +557,10 @@
         #[cfg(test)]
         let get_toml = |_| TomlConfig::default();
         #[cfg(not(test))]
-        let get_toml = |file: PathBuf| {
+        let get_toml = |file: &Path| {
             use std::process;
 
-            let contents = t!(fs::read_to_string(&file), "`include` config not found");
+            let contents = t!(fs::read_to_string(file), "`include` config not found");
             match toml::from_str(&contents) {
                 Ok(table) => table,
                 Err(err) => {
@@ -571,26 +570,24 @@
             }
         };
 
-        let mut toml = flags.config.map(get_toml).unwrap_or_else(TomlConfig::default);
+        let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default);
         if let Some(include) = &toml.profile {
             let mut include_path = config.src.clone();
             include_path.push("src");
             include_path.push("bootstrap");
             include_path.push("defaults");
-            include_path.push(format!("config.toml.{}", include));
-            let included_toml = get_toml(include_path);
+            include_path.push(format!("config.{}.toml", include));
+            let included_toml = get_toml(&include_path);
             toml.merge(included_toml);
         }
 
         config.changelog_seen = toml.changelog_seen;
+        if let Some(cfg) = flags.config {
+            config.config = cfg;
+        }
 
         let build = toml.build.unwrap_or_default();
 
-        // If --target was specified but --host wasn't specified, don't run any host-only tests.
-        let has_hosts = build.host.is_some() || flags.host.is_some();
-        let has_targets = build.target.is_some() || flags.target.is_some();
-        config.skip_only_host_steps = !has_hosts && has_targets;
-
         config.hosts = if let Some(arg_host) = flags.host {
             arg_host
         } else if let Some(file_host) = build.host {
@@ -738,7 +735,14 @@
             set(&mut config.llvm_use_libcxx, llvm.use_libcxx);
             config.llvm_use_linker = llvm.use_linker.clone();
             config.llvm_allow_old_toolchain = llvm.allow_old_toolchain;
-            config.llvm_from_ci = llvm.download_ci_llvm.unwrap_or(false);
+            config.llvm_from_ci = match llvm.download_ci_llvm {
+                Some(StringOrBool::String(s)) => {
+                    assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
+                    config.build.triple == "x86_64-unknown-linux-gnu"
+                }
+                Some(StringOrBool::Bool(b)) => b,
+                None => false,
+            };
 
             if config.llvm_from_ci {
                 // None of the LLVM options, except assertions, are supported
diff --git a/src/bootstrap/defaults/config.toml.codegen b/src/bootstrap/defaults/config.codegen.toml
similarity index 100%
rename from src/bootstrap/defaults/config.toml.codegen
rename to src/bootstrap/defaults/config.codegen.toml
diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml
new file mode 100644
index 0000000..0ca9288
--- /dev/null
+++ b/src/bootstrap/defaults/config.compiler.toml
@@ -0,0 +1,13 @@
+# These defaults are meant for contributors to the compiler who do not modify codegen or LLVM
+[rust]
+# This enables `RUSTC_LOG=debug`, avoiding confusing situations
+# where adding `debug!()` appears to do nothing.
+# However, it makes running the compiler slightly slower.
+debug-logging = true
+# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
+incremental = true
+
+[llvm]
+# Will download LLVM from CI if available on your platform (Linux only for now)
+# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms
+download-ci-llvm = "if-available"
diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml
new file mode 100644
index 0000000..9874fdb
--- /dev/null
+++ b/src/bootstrap/defaults/config.library.toml
@@ -0,0 +1,15 @@
+# These defaults are meant for contributors to the standard library and documentation.
+[build]
+# When building the standard library, you almost never want to build the compiler itself.
+build-stage = 0
+test-stage = 0
+bench-stage = 0
+
+[rust]
+# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
+incremental = true
+
+[llvm]
+# Will download LLVM from CI if available on your platform (Linux only for now)
+# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms
+download-ci-llvm = "if-available"
diff --git a/src/bootstrap/defaults/config.toml.compiler b/src/bootstrap/defaults/config.toml.compiler
deleted file mode 100644
index 4772de8..0000000
--- a/src/bootstrap/defaults/config.toml.compiler
+++ /dev/null
@@ -1,8 +0,0 @@
-# These defaults are meant for contributors to the compiler who do not modify codegen or LLVM
-[rust]
-# This enables `RUSTC_LOG=debug`, avoiding confusing situations
-# where adding `debug!()` appears to do nothing.
-# However, it makes running the compiler slightly slower.
-debug-logging = true
-# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
-incremental = true
diff --git a/src/bootstrap/defaults/config.toml.library b/src/bootstrap/defaults/config.toml.library
deleted file mode 100644
index e4316f4..0000000
--- a/src/bootstrap/defaults/config.toml.library
+++ /dev/null
@@ -1,10 +0,0 @@
-# These defaults are meant for contributors to the standard library and documentation.
-[build]
-# When building the standard library, you almost never want to build the compiler itself.
-build-stage = 0
-test-stage = 0
-bench-stage = 0
-
-[rust]
-# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
-incremental = true
diff --git a/src/bootstrap/defaults/config.toml.user b/src/bootstrap/defaults/config.user.toml
similarity index 100%
rename from src/bootstrap/defaults/config.toml.user
rename to src/bootstrap/defaults/config.user.toml
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index f1202c8..6d2da0c 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -26,27 +26,10 @@
 use time::{self, Timespec};
 
 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
-    if component == "cargo" {
-        format!("{}-{}", component, builder.cargo_package_vers())
-    } else if component == "rls" {
-        format!("{}-{}", component, builder.rls_package_vers())
-    } else if component == "rust-analyzer" {
-        format!("{}-{}", component, builder.rust_analyzer_package_vers())
-    } else if component == "clippy" {
-        format!("{}-{}", component, builder.clippy_package_vers())
-    } else if component == "miri" {
-        format!("{}-{}", component, builder.miri_package_vers())
-    } else if component == "rustfmt" {
-        format!("{}-{}", component, builder.rustfmt_package_vers())
-    } else if component == "llvm-tools" {
-        format!("{}-{}", component, builder.llvm_tools_package_vers())
-    } else {
-        assert!(component.starts_with("rust"));
-        format!("{}-{}", component, builder.rust_package_vers())
-    }
+    format!("{}-{}", component, builder.rust_package_vers())
 }
 
-fn distdir(builder: &Builder<'_>) -> PathBuf {
+pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf {
     builder.out.join("dist")
 }
 
@@ -2368,15 +2351,9 @@
         cmd.arg(sign);
         cmd.arg(distdir(builder));
         cmd.arg(today.trim());
-        cmd.arg(builder.rust_package_vers());
         cmd.arg(addr);
-        cmd.arg(builder.package_vers(&builder.release_num("cargo")));
-        cmd.arg(builder.package_vers(&builder.release_num("rls")));
-        cmd.arg(builder.package_vers(&builder.release_num("rust-analyzer/crates/rust-analyzer")));
-        cmd.arg(builder.package_vers(&builder.release_num("clippy")));
-        cmd.arg(builder.package_vers(&builder.release_num("miri")));
-        cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
-        cmd.arg(builder.llvm_tools_package_vers());
+        cmd.arg(&builder.config.channel);
+        cmd.env("BUILD_MANIFEST_LEGACY", "1");
 
         builder.create_dir(&distdir(builder));
 
@@ -2561,8 +2538,15 @@
         let dst_bindir = image.join("bin");
         t!(fs::create_dir_all(&dst_bindir));
 
-        let exe = builder.llvm_out(target).join("bin").join(exe("llvm-config", target));
-        builder.install(&exe, &dst_bindir, 0o755);
+        let src_bindir = builder.llvm_out(target).join("bin");
+        let install_bin =
+            |name| builder.install(&src_bindir.join(exe(name, target)), &dst_bindir, 0o755);
+        install_bin("llvm-config");
+        install_bin("llvm-ar");
+        install_bin("llvm-objdump");
+        install_bin("llvm-profdata");
+        install_bin("llvm-bcanalyzer");
+        install_bin("llvm-cov");
         builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755);
 
         // Copy the include directory as well; needed mostly to build
@@ -2606,3 +2590,70 @@
         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
     }
 }
+
+/// Tarball containing a prebuilt version of the build-manifest tool, intented to be used by the
+/// release process to avoid cloning the monorepo and building stuff.
+///
+/// Should not be considered stable by end users.
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct BuildManifest {
+    pub target: TargetSelection,
+}
+
+impl Step for BuildManifest {
+    type Output = PathBuf;
+    const DEFAULT: bool = false;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/build-manifest")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(BuildManifest { target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        let build_manifest = builder.tool_exe(Tool::BuildManifest);
+
+        let name = pkgname(builder, "build-manifest");
+        let tmp = tmpdir(builder);
+
+        // Prepare the image.
+        let image = tmp.join("build-manifest-image");
+        let image_bin = image.join("bin");
+        let _ = fs::remove_dir_all(&image);
+        t!(fs::create_dir_all(&image_bin));
+        builder.install(&build_manifest, &image_bin, 0o755);
+
+        // Prepare the overlay.
+        let overlay = tmp.join("build-manifest-overlay");
+        let _ = fs::remove_dir_all(&overlay);
+        builder.create_dir(&overlay);
+        builder.create(&overlay.join("version"), &builder.rust_version());
+        for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] {
+            builder.install(&builder.src.join(file), &overlay, 0o644);
+        }
+
+        // Create the final tarball.
+        let mut cmd = rust_installer(builder);
+        cmd.arg("generate")
+            .arg("--product-name=Rust")
+            .arg("--rel-manifest-dir=rustlib")
+            .arg("--success-message=build-manifest installed.")
+            .arg("--image-dir")
+            .arg(&image)
+            .arg("--work-dir")
+            .arg(&tmpdir(builder))
+            .arg("--output-dir")
+            .arg(&distdir(builder))
+            .arg("--non-installed-overlay")
+            .arg(&overlay)
+            .arg(format!("--package-name={}-{}", name, self.target.triple))
+            .arg("--legacy-manifest-dirs=rustlib,cargo")
+            .arg("--component-name=build-manifest");
+
+        builder.run(&mut cmd);
+        distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple))
+    }
+}
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
new file mode 100644
index 0000000..d857618
--- /dev/null
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -0,0 +1,4 @@
+Change this file to make users of the `download-ci-llvm` configuration download
+a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
+
+Last change is for: https://github.com/rust-lang/rust/pull/78131
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index a12fc50..22cfd0c 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -12,6 +12,7 @@
 
 use crate::builder::Builder;
 use crate::config::{Config, TargetSelection};
+use crate::setup::Profile;
 use crate::{Build, DocTests};
 
 /// Deserialized version of all flags for this compile.
@@ -29,6 +30,7 @@
     pub cmd: Subcommand,
     pub incremental: bool,
     pub exclude: Vec<PathBuf>,
+    pub include_default_paths: bool,
     pub rustc_error_format: Option<String>,
     pub json_output: bool,
     pub dry_run: bool,
@@ -47,6 +49,9 @@
         paths: Vec<PathBuf>,
     },
     Check {
+        // Whether to run checking over all targets (e.g., unit / integration
+        // tests).
+        all_targets: bool,
         paths: Vec<PathBuf>,
     },
     Clippy {
@@ -91,7 +96,7 @@
         paths: Vec<PathBuf>,
     },
     Setup {
-        path: String,
+        profile: Profile,
     },
 }
 
@@ -120,6 +125,7 @@
     dist        Build distribution artifacts
     install     Install distribution artifacts
     run, r      Run tools contained in this repository
+    setup       Create a config.toml (making it easier to use `x.py` itself)
 
 To learn more about a subcommand, run `./x.py <subcommand> -h`",
         );
@@ -133,6 +139,11 @@
         opts.optmulti("", "host", "host targets to build", "HOST");
         opts.optmulti("", "target", "target targets to build", "TARGET");
         opts.optmulti("", "exclude", "build paths to exclude", "PATH");
+        opts.optflag(
+            "",
+            "include-default-paths",
+            "include default paths in addition to the provided ones",
+        );
         opts.optopt("", "on-fail", "command to run on failure", "CMD");
         opts.optflag("", "dry-run", "dry run; don't build anything");
         opts.optopt(
@@ -250,6 +261,9 @@
                         `/<build_base>/rustfix_missing_coverage.txt`",
                 );
             }
+            "check" | "c" => {
+                opts.optflag("", "all-targets", "Check all targets");
+            }
             "bench" => {
                 opts.optmulti("", "test-args", "extra arguments", "ARGS");
             }
@@ -459,15 +473,21 @@
                 );
             }
             "setup" => {
-                subcommand_help.push_str(
+                subcommand_help.push_str(&format!(
                     "\n
+x.py setup creates a `config.toml` which changes the defaults for x.py itself.
+
 Arguments:
     This subcommand accepts a 'profile' to use for builds. For example:
 
         ./x.py setup library
 
-    The profile is optional and you will be prompted interactively if it is not given.",
-                );
+    The profile is optional and you will be prompted interactively if it is not given.
+    The following profiles are available:
+
+{}",
+                    Profile::all_for_help("        ").trim_end()
+                ));
             }
             _ => {}
         };
@@ -484,7 +504,9 @@
 
         let cmd = match subcommand.as_str() {
             "build" | "b" => Subcommand::Build { paths },
-            "check" | "c" => Subcommand::Check { paths },
+            "check" | "c" => {
+                Subcommand::Check { paths, all_targets: matches.opt_present("all-targets") }
+            }
             "clippy" => Subcommand::Clippy { paths },
             "fix" => Subcommand::Fix { paths },
             "test" | "t" => Subcommand::Test {
@@ -525,18 +547,24 @@
                 Subcommand::Run { paths }
             }
             "setup" => {
-                let path = if paths.len() > 1 {
+                let profile = if paths.len() > 1 {
                     println!("\nat most one profile can be passed to setup\n");
                     usage(1, &opts, verbose, &subcommand_help)
                 } else if let Some(path) = paths.pop() {
-                    t!(path.into_os_string().into_string().map_err(|path| format!(
-                        "{} is not a valid UTF8 string",
-                        path.to_string_lossy()
-                    )))
+                    let profile_string = t!(path.into_os_string().into_string().map_err(
+                        |path| format!("{} is not a valid UTF8 string", path.to_string_lossy())
+                    ));
+
+                    profile_string.parse().unwrap_or_else(|err| {
+                        eprintln!("error: {}", err);
+                        eprintln!("help: the available profiles are:");
+                        eprint!("{}", Profile::all_for_help("- "));
+                        std::process::exit(1);
+                    })
                 } else {
                     t!(crate::setup::interactive_path())
                 };
-                Subcommand::Setup { path }
+                Subcommand::Setup { profile }
             }
             _ => {
                 usage(1, &opts, verbose, &subcommand_help);
@@ -601,6 +629,7 @@
                 .into_iter()
                 .map(|p| p.into())
                 .collect::<Vec<_>>(),
+            include_default_paths: matches.opt_present("include-default-paths"),
             deny_warnings: parse_deny_warnings(&matches),
             llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map(
                 |s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"),
@@ -679,7 +708,7 @@
 }
 
 fn split(s: &[String]) -> Vec<String> {
-    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
+    s.iter().flat_map(|s| s.split(',')).filter(|s| !s.is_empty()).map(|s| s.to_string()).collect()
 }
 
 fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 4cc72f5..22a8e82 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -177,8 +177,13 @@
     "llvm-size", // used to prints the size of the linker sections of a program
     "llvm-strip", // used to discard symbols from binary files to reduce their size
     "llvm-ar", // used for creating and modifying archive files
+    "llvm-dis", // used to disassemble LLVM bitcode
+    "llc",     // used to compile LLVM bytecode
+    "opt",     // used to optimize LLVM bytecode
 ];
 
+pub const VERSION: usize = 2;
+
 /// A structure representing a Rust compiler.
 ///
 /// Each compiler has a `stage` that it is associated with and a `host` that
@@ -471,8 +476,8 @@
             return clean::clean(self, all);
         }
 
-        if let Subcommand::Setup { path: include_name } = &self.config.cmd {
-            return setup::setup(&self.config.src, include_name);
+        if let Subcommand::Setup { profile } = &self.config.cmd {
+            return setup::setup(&self.config.src, *profile);
         }
 
         {
@@ -1051,40 +1056,6 @@
         self.package_vers(&self.version)
     }
 
-    /// Returns the value of `package_vers` above for Cargo
-    fn cargo_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("cargo"))
-    }
-
-    /// Returns the value of `package_vers` above for rls
-    fn rls_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("rls"))
-    }
-
-    /// Returns the value of `package_vers` above for rust-analyzer
-    fn rust_analyzer_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("rust-analyzer/crates/rust-analyzer"))
-    }
-
-    /// Returns the value of `package_vers` above for clippy
-    fn clippy_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("clippy"))
-    }
-
-    /// Returns the value of `package_vers` above for miri
-    fn miri_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("miri"))
-    }
-
-    /// Returns the value of `package_vers` above for rustfmt
-    fn rustfmt_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("rustfmt"))
-    }
-
-    fn llvm_tools_package_vers(&self) -> String {
-        self.package_vers(&self.version)
-    }
-
     fn llvm_tools_vers(&self) -> String {
         self.rust_version()
     }
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 6bba00e..37d6fab 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -378,6 +378,8 @@
             cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD");
         } else if target.contains("windows") {
             cfg.define("CMAKE_SYSTEM_NAME", "Windows");
+        } else if target.contains("haiku") {
+            cfg.define("CMAKE_SYSTEM_NAME", "Haiku");
         }
         // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in
         // that case like CMake we cannot easily determine system version either.
diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs
index ba593ca..7c64e5a 100644
--- a/src/bootstrap/run.rs
+++ b/src/bootstrap/run.rs
@@ -1,5 +1,7 @@
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::dist::distdir;
 use crate::tool::Tool;
+use build_helper::output;
 use std::process::Command;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -41,3 +43,42 @@
     }
     true
 }
+
+#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct BuildManifest;
+
+impl Step for BuildManifest {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/build-manifest")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(BuildManifest);
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        // This gets called by `promote-release`
+        // (https://github.com/rust-lang/promote-release).
+        let mut cmd = builder.tool_cmd(Tool::BuildManifest);
+        let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
+            panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
+        });
+        let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
+            panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
+        });
+
+        let today = output(Command::new("date").arg("+%Y-%m-%d"));
+
+        cmd.arg(sign);
+        cmd.arg(distdir(builder));
+        cmd.arg(today.trim());
+        cmd.arg(addr);
+        cmd.arg(&builder.config.channel);
+
+        builder.create_dir(&distdir(builder));
+        builder.run(&mut cmd);
+    }
+}
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 9d3a889..c6e1c99 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -1,11 +1,78 @@
-use crate::t;
+use crate::{t, VERSION};
+use std::fmt::Write as _;
 use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::str::FromStr;
 use std::{
-    env, fs,
+    env, fmt, fs,
     io::{self, Write},
 };
 
-pub fn setup(src_path: &Path, include_name: &str) {
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub enum Profile {
+    Compiler,
+    Codegen,
+    Library,
+    User,
+}
+
+impl Profile {
+    fn include_path(&self, src_path: &Path) -> PathBuf {
+        PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
+    }
+
+    pub fn all() -> impl Iterator<Item = Self> {
+        use Profile::*;
+        // N.B. these are ordered by how they are displayed, not alphabetically
+        [Library, Compiler, Codegen, User].iter().copied()
+    }
+
+    pub fn purpose(&self) -> String {
+        use Profile::*;
+        match self {
+            Library => "Contribute to the standard library",
+            Compiler => "Contribute to the compiler or rustdoc",
+            Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
+            User => "Install Rust from source",
+        }
+        .to_string()
+    }
+
+    pub fn all_for_help(indent: &str) -> String {
+        let mut out = String::new();
+        for choice in Profile::all() {
+            writeln!(&mut out, "{}{}: {}", indent, choice, choice.purpose()).unwrap();
+        }
+        out
+    }
+}
+
+impl FromStr for Profile {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "lib" | "library" => Ok(Profile::Library),
+            "compiler" | "rustdoc" => Ok(Profile::Compiler),
+            "llvm" | "codegen" => Ok(Profile::Codegen),
+            "maintainer" | "user" => Ok(Profile::User),
+            _ => Err(format!("unknown profile: '{}'", s)),
+        }
+    }
+}
+
+impl fmt::Display for Profile {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Profile::Compiler => write!(f, "compiler"),
+            Profile::Codegen => write!(f, "codegen"),
+            Profile::Library => write!(f, "library"),
+            Profile::User => write!(f, "user"),
+        }
+    }
+}
+
+pub fn setup(src_path: &Path, profile: Profile) {
     let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
 
     if cfg_file.as_ref().map_or(false, |f| f.exists()) {
@@ -14,15 +81,10 @@
             "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
             file.display()
         );
+        println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
         println!(
-            "help: try adding `profile = \"{}\"` at the top of {}",
-            include_name,
-            file.display()
-        );
-        println!(
-            "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}",
-            src_path.display(),
-            include_name
+            "note: this will use the configuration in {}",
+            profile.include_path(src_path).display()
         );
         std::process::exit(1);
     }
@@ -30,28 +92,33 @@
     let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
     let settings = format!(
         "# Includes one of the default files in src/bootstrap/defaults\n\
-    profile = \"{}\"\n",
-        include_name
+    profile = \"{}\"\n\
+    changelog-seen = {}\n",
+        profile, VERSION
     );
     t!(fs::write(path, settings));
 
-    let include_path =
-        format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name);
-    println!("`x.py` will now use the configuration at {}", include_path);
+    let include_path = profile.include_path(src_path);
+    println!("`x.py` will now use the configuration at {}", include_path.display());
 
-    let suggestions = match include_name {
-        "codegen" | "compiler" => &["check", "build", "test"][..],
-        "library" => &["check", "build", "test library/std", "doc"],
-        "user" => &["dist", "build"],
-        _ => return,
+    let suggestions = match profile {
+        Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
+        Profile::Library => &["check", "build", "test library/std", "doc"],
+        Profile::User => &["dist", "build"],
     };
 
+    println!();
+
+    t!(install_git_hook_maybe(src_path));
+
+    println!();
+
     println!("To get started, try one of the following commands:");
     for cmd in suggestions {
         println!("- `x.py {}`", cmd);
     }
 
-    if include_name != "user" {
+    if profile != Profile::User {
         println!(
             "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
         );
@@ -59,24 +126,67 @@
 }
 
 // Used to get the path for `Subcommand::Setup`
-pub fn interactive_path() -> io::Result<String> {
+pub fn interactive_path() -> io::Result<Profile> {
+    fn abbrev_all() -> impl Iterator<Item = (String, Profile)> {
+        ('a'..).map(|c| c.to_string()).zip(Profile::all())
+    }
+
+    fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
+        let input = input.trim().to_lowercase();
+        for (letter, profile) in abbrev_all() {
+            if input == letter {
+                return Ok(profile);
+            }
+        }
+        input.parse()
+    }
+
+    println!("Welcome to the Rust project! What do you want to do with x.py?");
+    for (letter, profile) in abbrev_all() {
+        println!("{}) {}: {}", letter, profile, profile.purpose());
+    }
+    let template = loop {
+        print!(
+            "Please choose one ({}): ",
+            abbrev_all().map(|(l, _)| l).collect::<Vec<_>>().join("/")
+        );
+        io::stdout().flush()?;
+        let mut input = String::new();
+        io::stdin().read_line(&mut input)?;
+        if input == "" {
+            eprintln!("EOF on stdin, when expecting answer to question.  Giving up.");
+            std::process::exit(1);
+        }
+        break match parse_with_abbrev(&input) {
+            Ok(profile) => profile,
+            Err(err) => {
+                println!("error: {}", err);
+                println!("note: press Ctrl+C to exit");
+                continue;
+            }
+        };
+    };
+    Ok(template)
+}
+
+// install a git hook to automatically run tidy --bless, if they want
+fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
     let mut input = String::new();
     println!(
-        "Welcome to the Rust project! What do you want to do with x.py?
-a) Contribute to the standard library
-b) Contribute to the compiler
-c) Contribute to the compiler, and also modify LLVM or codegen
-d) Install Rust from source"
+        "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
+If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` on each commit
+to ensure your code is up to par. If you decide later that this behavior is undesirable,
+simply delete the `pre-commit` file from .git/hooks."
     );
-    let template = loop {
-        print!("Please choose one (a/b/c/d): ");
+
+    let should_install = loop {
+        print!("Would you like to install the git hook?: [y/N] ");
         io::stdout().flush()?;
+        input.clear();
         io::stdin().read_line(&mut input)?;
         break match input.trim().to_lowercase().as_str() {
-            "a" | "lib" | "library" => "library",
-            "b" | "compiler" => "compiler",
-            "c" | "llvm" => "llvm",
-            "d" | "user" | "maintainer" => "maintainer",
+            "y" | "yes" => true,
+            "n" | "no" | "" => false,
             _ => {
                 println!("error: unrecognized option '{}'", input.trim());
                 println!("note: press Ctrl+C to exit");
@@ -84,5 +194,25 @@
             }
         };
     };
-    Ok(template.to_owned())
+
+    Ok(if should_install {
+        let src = src_path.join("src").join("etc").join("pre-commit.sh");
+        let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map(
+            |output| {
+                assert!(output.status.success(), "failed to run `git`");
+                PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
+            }
+        ));
+        let dst = git.join("hooks").join("pre-commit");
+        match fs::hard_link(src, &dst) {
+            Err(e) => println!(
+                "error: could not create hook {}: do you already have the git hook installed?\n{}",
+                dst.display(),
+                e
+            ),
+            Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"),
+        };
+    } else {
+        println!("Ok, skipping installation!");
+    })
 }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 00522ee..33e85dc 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -737,6 +737,7 @@
         let mut cmd = builder.tool_cmd(Tool::Tidy);
         cmd.arg(&builder.src);
         cmd.arg(&builder.initial_cargo);
+        cmd.arg(&builder.out);
         if builder.is_verbose() {
             cmd.arg("--verbose");
         }
@@ -966,6 +967,15 @@
     /// compiletest `mode` and `suite` arguments. For example `mode` can be
     /// "run-pass" or `suite` can be something like `debuginfo`.
     fn run(self, builder: &Builder<'_>) {
+        if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
+            eprintln!("\
+error: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
+help: use `--stage 1` instead
+note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
+            );
+            std::process::exit(1);
+        }
+
         let compiler = self.compiler;
         let target = self.target;
         let mode = self.mode;
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index a307ef3..b35d1b9 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -122,7 +122,7 @@
     fn drop(&mut self) {
         let time = self.1.elapsed();
         if !self.0 {
-            println!("\tfinished in {}.{:03}", time.as_secs(), time.subsec_millis());
+            println!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis());
         }
     }
 }
diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml
index 05177e5..37c2e9b 100644
--- a/src/ci/azure-pipelines/auto.yml
+++ b/src/ci/azure-pipelines/auto.yml
@@ -18,45 +18,9 @@
   - auto
 
 jobs:
-- job: macOS
+- job: Dummy
   timeoutInMinutes: 600
   pool:
-    vmImage: macos-10.15
+    vmImage: ubuntu-16.04
   steps:
-  - template: steps/run.yml
-  variables:
-    # We're still uploading macOS builds from Azure Pipelines.
-    - group: prod-credentials
-  strategy:
-    matrix:
-      # OSX builders running tests, these run the full test suite.
-      # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some
-      # runners that run `//ignore-debug` tests.
-      #
-      # Note that the compiler is compiled to target 10.8 here because the Xcode
-      # version that we're using, 8.2, cannot compile LLVM for OSX 10.7.
-      x86_64-apple:
-        SCRIPT: ./x.py --stage 2 test
-        INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
-        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-        MACOSX_DEPLOYMENT_TARGET: 10.8
-        MACOSX_STD_DEPLOYMENT_TARGET: 10.7
-        NO_LLVM_ASSERTIONS: 1
-        NO_DEBUG_ASSERTIONS: 1
-
-      dist-x86_64-apple:
-        SCRIPT: ./x.py dist
-        INITIAL_RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
-        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-        MACOSX_DEPLOYMENT_TARGET: 10.7
-        NO_LLVM_ASSERTIONS: 1
-        NO_DEBUG_ASSERTIONS: 1
-        DIST_REQUIRE_ALL_TOOLS: 1
-
-      dist-x86_64-apple-alt:
-        SCRIPT: ./x.py dist
-        INITIAL_RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
-        RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-        MACOSX_DEPLOYMENT_TARGET: 10.7
-        NO_LLVM_ASSERTIONS: 1
-        NO_DEBUG_ASSERTIONS: 1
+  - bash: echo "We're running this job since bors is still gating on Azure"
diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml
deleted file mode 100644
index 34fc4d7..0000000
--- a/src/ci/azure-pipelines/steps/run.yml
+++ /dev/null
@@ -1,142 +0,0 @@
-#####################################
-##    READ BEFORE CHANGING THIS    ##
-#####################################
-
-# We're in the process of evaluating GitHub Actions as a possible replacement
-# for Azure Pipelines, and at the moment the configuration is duplicated
-# between the two CI providers. Be sure to also change the configuration in
-# src/ci/github-actions when changing this file.
-
-#####################################
-
-# FIXME(linux): need to configure core dumps, enable them, and then dump
-# backtraces on failure from all core dumps:
-#
-# - bash: sudo apt install gdb
-# - bash: sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern'
-#
-# Check travis config for `gdb --batch` command to print all crash logs
-
-steps:
-
-# Configure our CI_JOB_NAME variable which log analyzers can use for the main
-# step to see what's going on.
-- bash: |
-    builder=$(echo $AGENT_JOBNAME | cut -d ' ' -f 2)
-    echo "##vso[task.setvariable variable=CI_JOB_NAME]$builder"
-  displayName: Configure Job Name
-
-# Disable automatic line ending conversion, which is enabled by default on
-# Azure's Windows image. Having the conversion enabled caused regressions both
-# in our test suite (it broke miri tests) and in the ecosystem, since we
-# started shipping install scripts with CRLF endings instead of the old LF.
-#
-# Note that we do this a couple times during the build as the PATH and current
-# user/directory change, e.g. when mingw is enabled.
-- bash: git config --global core.autocrlf false
-  displayName: "Disable git automatic line ending conversion"
-
-- checkout: self
-  fetchDepth: 2
-
-- bash: src/ci/scripts/setup-environment.sh
-  displayName: Setup environment
-
-- bash: src/ci/scripts/clean-disk.sh
-  displayName: Clean disk
-
-- bash: src/ci/scripts/should-skip-this.sh
-  displayName: Decide whether to run this job
-
-- bash: src/ci/scripts/collect-cpu-stats.sh
-  displayName: Collect CPU-usage statistics in the background
-
-- bash: src/ci/scripts/dump-environment.sh
-  displayName: Show the current environment
-
-- bash: src/ci/scripts/install-sccache.sh
-  displayName: Install sccache
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/install-clang.sh
-  displayName: Install clang
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/install-wix.sh
-  displayName: Install wix
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/symlink-build-dir.sh
-  displayName: Ensure the build happens on a partition with enough space
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/disable-git-crlf-conversion.sh
-  displayName: "Disable git automatic line ending conversion (on C:/)"
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/install-msys2.sh
-  displayName: Install msys2
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/install-mingw.sh
-  displayName: Install MinGW
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/install-ninja.sh
-  displayName: Install ninja
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/enable-docker-ipv6.sh
-  displayName: Enable IPv6 on Docker
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-# Disable automatic line ending conversion (again). On Windows, when we're
-# installing dependencies, something switches the git configuration directory or
-# re-enables autocrlf. We've not tracked down the exact cause -- and there may
-# be multiple -- but this should ensure submodules are checked out with the
-# appropriate line endings.
-- bash: src/ci/scripts/disable-git-crlf-conversion.sh
-  displayName: Disable git automatic line ending conversion
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/checkout-submodules.sh
-  displayName: Checkout submodules
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-- bash: src/ci/scripts/verify-line-endings.sh
-  displayName: Verify line endings
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-
-# Ensure the `aws` CLI is installed so we can deploy later on, cache docker
-# images, etc.
-- bash: src/ci/scripts/install-awscli.sh
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-  displayName: Install awscli
-
-- bash: src/ci/scripts/run-build-from-ci.sh
-  timeoutInMinutes: 600
-  env:
-    AWS_ACCESS_KEY_ID: $(SCCACHE_AWS_ACCESS_KEY_ID)
-    AWS_SECRET_ACCESS_KEY: $(SCCACHE_AWS_SECRET_ACCESS_KEY)
-    TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
-  condition: and(succeeded(), not(variables.SKIP_JOB))
-  displayName: Run build
-
-- bash: src/ci/scripts/upload-artifacts.sh
-  env:
-    AWS_ACCESS_KEY_ID: $(UPLOAD_AWS_ACCESS_KEY_ID)
-    AWS_SECRET_ACCESS_KEY: $(UPLOAD_AWS_SECRET_ACCESS_KEY)
-  displayName: Upload artifacts
-  # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy
-  # builders *should* have the AWS credentials available. Still, explicitly
-  # adding the condition is helpful as this way CI will not silently skip
-  # deploying artifacts from a dist builder if the variables are misconfigured,
-  # erroring about invalid credentials instead.
-  condition: |
-    and(
-      succeeded(), not(variables.SKIP_JOB),
-      or(
-        variables.UPLOAD_AWS_SECRET_ACCESS_KEY,
-        eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')
-      )
-    )
diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile
index add2647..f675252 100644
--- a/src/ci/docker/host-x86_64/arm-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile
@@ -31,7 +31,7 @@
 
 ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14
 
-ENV SCRIPT python3 ../x.py --stage 2 test --target $TARGETS
+ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
diff --git a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile
index f1ccbc9..9fb5faf 100644
--- a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile
@@ -79,6 +79,6 @@
 RUN sh /scripts/sccache.sh
 
 ENV RUST_CONFIGURE_ARGS --qemu-armhf-rootfs=/tmp/rootfs
-ENV SCRIPT python3 ../x.py --stage 2 test --target arm-unknown-linux-gnueabihf
+ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target arm-unknown-linux-gnueabihf
 
 ENV NO_CHANGE_USER=1
diff --git a/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile b/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile
index 6335dc0..e04f640 100644
--- a/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile
+++ b/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile
@@ -34,7 +34,7 @@
 # Emscripten installation is user-specific
 ENV NO_CHANGE_USER=1
 
-ENV SCRIPT python3 ../x.py --stage 2 test --target $TARGETS
+ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
 
 # This is almost identical to the wasm32-unknown-emscripten target, so
 # running with assertions again is not useful
diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile
index b32c498..e9188b4 100644
--- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile
+++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile
@@ -19,4 +19,4 @@
     CXX_x86_64_unknown_redox=x86_64-unknown-redox-g++
 
 ENV RUST_CONFIGURE_ARGS --enable-extended
-ENV SCRIPT python3 ../x.py dist --target x86_64-unknown-redox
+ENV SCRIPT python3 ../x.py dist --host='' --target x86_64-unknown-redox
diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile
index 3c39a63..f3f52ed 100644
--- a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile
@@ -84,9 +84,9 @@
 # download and build the riscv bootloader
 RUN git clone https://github.com/riscv/riscv-pk
 WORKDIR /tmp/riscv-pk
-# nothing special about this revision: it is just master at the time of writing
-# v1.0.0 doesn't build
-RUN git checkout 5d9ed238e1cabfbca3c47f50d32894ce94bfc304
+# This revision fixes a fault in recent QEMU from 64-bit accesses to the PLIC
+# commits later than this one should work too
+RUN git checkout 7d8b7c0dab72108e3ea7bb7744d3f6cc907c7ef4
 RUN mkdir build && cd build && \
     ../configure --with-payload=/tmp/vmlinux --host=riscv64-linux-gnu && \
     make -j$(nproc) && \
diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile
index 6d38e19..258dcea 100644
--- a/src/ci/docker/host-x86_64/dist-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile
@@ -32,7 +32,7 @@
       --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
       --disable-docs
 
-ENV SCRIPT python3 ../x.py dist --target $TARGETS
+ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
diff --git a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
index 995f7c3..c734202 100644
--- a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
@@ -47,5 +47,5 @@
 ENV TARGETS=i586-unknown-linux-gnu,i686-unknown-linux-musl
 
 ENV SCRIPT \
-      python3 ../x.py --stage 2 test --target $TARGETS && \
-      python3 ../x.py dist --target $TARGETS,i586-unknown-linux-musl
+      python3 ../x.py --stage 2 test --host='' --target $TARGETS && \
+      python3 ../x.py dist --host='' --target $TARGETS,i586-unknown-linux-musl
diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
index 4318926..104b608 100644
--- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
@@ -187,8 +187,8 @@
       --disable-docs
 
 ENV SCRIPT \
-      python3 ../x.py --stage 2 test --target $RUN_MAKE_TARGETS src/test/run-make && \
-      python3 ../x.py dist --target $TARGETS
+      python3 ../x.py --stage 2 test --host='' --target $RUN_MAKE_TARGETS src/test/run-make && \
+      python3 ../x.py dist --host='' --target $TARGETS
 
 # sccache
 COPY scripts/sccache.sh /scripts/
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 3081f29..47a66f7 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -110,4 +110,4 @@
   --set target.wasm32-wasi.wasi-root=/wasm32-wasi \
   --musl-root-armv7=/musl-armv7
 
-ENV SCRIPT python3 ../x.py dist --target $TARGETS
+ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
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 58e2567..14700ae 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
@@ -98,7 +98,9 @@
       --set llvm.thin-lto=true \
       --set llvm.ninja=false \
       --set rust.jemalloc
-ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \
+        --include-default-paths \
+        src/tools/build-manifest
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
 
 # This is the only builder which will create source tarballs
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index 8fc9a00..b2aa584 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -24,7 +24,7 @@
 
 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
-           python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
+           python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu --all-targets && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
            python3 ../x.py test --stage 2 src/tools/tidy && \
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 8c606d8..8653aec 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -41,7 +41,7 @@
 ENV NO_DEBUG_ASSERTIONS=1
 
 ENV WASM_TARGETS=wasm32-unknown-unknown
-ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --target $WASM_TARGETS \
+ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
   src/test/run-make \
   src/test/ui \
   src/test/compile-fail \
@@ -50,13 +50,13 @@
   library/core
 
 ENV NVPTX_TARGETS=nvptx64-nvidia-cuda
-ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --target $NVPTX_TARGETS \
+ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \
   src/test/run-make \
   src/test/assembly
 
 ENV MUSL_TARGETS=x86_64-unknown-linux-musl \
     CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \
     CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++
-ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --target $MUSL_TARGETS
+ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS
 
 ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT
diff --git a/src/ci/docker/host-x86_64/wasm32/Dockerfile b/src/ci/docker/host-x86_64/wasm32/Dockerfile
index b4c783c..096b664 100644
--- a/src/ci/docker/host-x86_64/wasm32/Dockerfile
+++ b/src/ci/docker/host-x86_64/wasm32/Dockerfile
@@ -53,7 +53,7 @@
 
 # FIXME: Re-enable these tests once https://github.com/rust-lang/cargo/pull/7476
 # is picked up by CI
-ENV SCRIPT python3 ../x.py test --stage 2 --target $TARGETS \
+ENV SCRIPT python3 ../x.py test --stage 2 --host='' --target $TARGETS \
     --exclude library/core \
     --exclude library/alloc \
     --exclude library/proc_macro \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile
index 0c9d6ed..34c6396 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile
@@ -45,7 +45,7 @@
            # on the `x86_64` host when they're built as `armv5te` binaries.
            # (we're only interested in the MIR output, so this doesn't matter)
            python2.7 ../x.py --stage 2 test src/test/mir-opt --pass=build \
-                                  --target=armv5te-unknown-linux-gnueabi && \
+                             --host='' --target=armv5te-unknown-linux-gnueabi && \
            # Run the UI test suite again, but in `--pass=check` mode
            #
            # This is intended to make sure that both `--pass=check` continues to
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index ea7e65a..01f15a8 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -149,6 +149,10 @@
         run: src/ci/scripts/install-sccache.sh
         <<: *step
 
+      - name: select Xcode
+        run: src/ci/scripts/select-xcode.sh
+        <<: *step
+
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         <<: *step
@@ -284,18 +288,6 @@
               CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
             <<: *job-linux-xl
 
-  try:
-    <<: *base-ci-job
-    name: try
-    env:
-      <<: [*shared-ci-variables, *prod-variables]
-    if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'
-    strategy:
-      matrix:
-        include:
-          - name: dist-x86_64-linux
-            <<: *job-linux-xl
-
   auto:
     <<: *base-ci-job
     name: auto
@@ -378,7 +370,8 @@
           - name: dist-x86_64-illumos
             <<: *job-linux-xl
 
-          - name: dist-x86_64-linux
+          - &dist-x86_64-linux
+            name: dist-x86_64-linux
             <<: *job-linux-xl
 
           - name: dist-x86_64-linux-alt
@@ -468,6 +461,37 @@
               NO_DEBUG_ASSERTIONS: 1
             <<: *job-macos-xl
 
+          # This target only needs to support 11.0 and up as nothing else supports the hardware
+          - name: dist-aarch64-apple
+            env:
+              SCRIPT: ./x.py dist --stage 2
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-apple-darwin
+                --host=aarch64-apple-darwin
+                --target=aarch64-apple-darwin
+                --enable-full-tools
+                --enable-sanitizers
+                --enable-profiler
+                --set rust.jemalloc
+                --set llvm.ninja=false
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              SELECT_XCODE: /Applications/Xcode_12.2.app
+              USE_XCODE_CLANG: 1
+              MACOSX_DEPLOYMENT_TARGET: 11.0
+              MACOSX_STD_DEPLOYMENT_TARGET: 11.0
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+              # Corresponds to 16K page size
+              #
+              # Shouldn't be needed if jemalloc-sys is updated to
+              # handle this platform like iOS or if we build on
+              # aarch64-apple-darwin itself.
+              #
+              # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237
+              JEMALLOC_SYS_WITH_LG_PAGE: 14
+            <<: *job-macos-xl
+
           ######################
           #  Windows Builders  #
           ######################
@@ -576,7 +600,7 @@
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-pc-windows-msvc
                 --host=x86_64-pc-windows-msvc
-                --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
+                --target=x86_64-pc-windows-msvc
                 --enable-full-tools
                 --enable-profiler
               SCRIPT: python x.py dist
@@ -595,6 +619,18 @@
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
 
+          - name: dist-aarch64-msvc
+            env:
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-msvc
+                --host=aarch64-pc-windows-msvc
+                --enable-full-tools
+                --enable-profiler
+              SCRIPT: python x.py dist
+              # RLS does not build for aarch64-pc-windows-msvc. See rust-lang/rls#1693
+              DIST_REQUIRE_ALL_TOOLS: 0
+            <<: *job-windows-xl
+
           - name: dist-i686-mingw
             env:
               RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
@@ -634,6 +670,17 @@
           - name: aarch64-gnu
             <<: *job-aarch64-linux
 
+  try:
+    <<: *base-ci-job
+    name: try
+    env:
+      <<: [*shared-ci-variables, *prod-variables]
+    if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'
+    strategy:
+      matrix:
+        include:
+          - *dist-x86_64-linux
+
   master:
     name: master
     runs-on: ubuntu-latest
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 5231aa2..181a7fc 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -104,6 +104,8 @@
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools"
 fi
 
+export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1
+
 # Print the date from the local machine and the date from an external source to
 # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure
 # Pipelines it happened that the certificates were marked as expired.
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index a1481f2..8070e90 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -12,10 +12,18 @@
 LLVM_VERSION="10.0.0"
 
 if isMacOS; then
-    curl -f "${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" | tar xJf -
+    # 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"
+        curl -f "${file}" | tar xJf -
+        bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin"
+    fi
 
-    ciCommandSetEnv CC "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang"
-    ciCommandSetEnv CXX "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang++"
+    ciCommandSetEnv CC "${bindir}/clang"
+    ciCommandSetEnv CXX "${bindir}/clang++"
 
     # macOS 10.15 onwards doesn't have libraries in /usr/include anymore: those
     # are now located deep into the filesystem, under Xcode's own files. The
diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh
index ae85d5c..1685fbb 100755
--- a/src/ci/scripts/install-mingw.sh
+++ b/src/ci/scripts/install-mingw.sh
@@ -42,6 +42,13 @@
             arch=x86_64
             mingw_archive="${MINGW_ARCHIVE_64}"
             ;;
+        *aarch64*)
+            # aarch64 is a cross-compiled target. Use the x86_64
+            # mingw, since that's the host architecture.
+            bits=64
+            arch=x86_64
+            mingw_archive="${MINGW_ARCHIVE_64}"
+            ;;
         *)
             echo "src/ci/scripts/install-mingw.sh can't detect the builder's architecture"
             echo "please tweak it to recognize the builder named '${CI_JOB_NAME}'"
diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh
new file mode 100755
index 0000000..3b9c77d
--- /dev/null
+++ b/src/ci/scripts/select-xcode.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+# This script selects the Xcode instance to use.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+
+if isMacOS; then
+    if [[ -s "${SELECT_XCODE-}" ]]; then
+        sudo xcode-select -s "${SELECT_XCODE}"
+    fi
+fi
diff --git a/src/ci/shared.sh b/src/ci/shared.sh
index 8222758..c93d477 100644
--- a/src/ci/shared.sh
+++ b/src/ci/shared.sh
@@ -104,7 +104,7 @@
     if isAzurePipelines; then
         echo "##vso[task.prependpath]${path}"
     elif isGitHubActions; then
-        echo "::add-path::${path}"
+        echo "${path}" >> "${GITHUB_PATH}"
     else
         echo "ciCommandAddPath only works inside CI!"
         exit 1
@@ -122,7 +122,7 @@
     if isAzurePipelines; then
         echo "##vso[task.setvariable variable=${name}]${value}"
     elif isGitHubActions; then
-        echo "::set-env name=${name}::${value}"
+        echo "${name}=${value}" >> "${GITHUB_ENV}"
     else
         echo "ciCommandSetEnv only works inside CI!"
         exit 1
diff --git a/src/doc/book b/src/doc/book
index cb28dee..451a1e3 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit cb28dee95e5e50b793e6ba9291c5d1568d3ad72e
+Subproject commit 451a1e30f2dd137aa04e142414eafb8d05f87f84
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
index 0cd2ca1..ca8169e 160000
--- a/src/doc/embedded-book
+++ b/src/doc/embedded-book
@@ -1 +1 @@
-Subproject commit 0cd2ca116274b915924c3a7e07c1e046b6f19b77
+Subproject commit ca8169e69b479f615855d0eece7e318138fcfc00
diff --git a/src/doc/reference b/src/doc/reference
index 56a13c0..1b78182 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 56a13c082ee90736c08d6abdcd90462517b703d3
+Subproject commit 1b78182e71709169dc0f1c3acdc4541b6860e1c4
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 19f0a03..1524759 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 19f0a0372af497b34369cf182d9d16156cab2969
+Subproject commit 152475937a8d8a1f508d8eeb57db79139bc803d9
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index bed10ca..f6493e4 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -497,8 +497,10 @@
 This instructs `rustc` to generate code specifically for a particular processor.
 
 You can run `rustc --print target-cpus` to see the valid options to pass
-here. Additionally, `native` can be passed to use the processor of the host
-machine. Each target has a default base CPU.
+here. Each target has a default base CPU. Special values include:
+
+* `native` can be passed to use the processor of the host machine. 
+* `generic` refers to an LLVM target with minimal features but modern tuning.
 
 ## target-feature
 
@@ -530,6 +532,20 @@
 Each target and [`target-cpu`](#target-cpu) has a default set of enabled
 features.
 
+## tune-cpu
+
+This instructs `rustc` to schedule code specifically for a particular
+processor. This does not affect the compatibility (instruction sets or ABI),
+but should make your code slightly more efficient on the selected CPU.
+
+The valid options are the same as those for [`target-cpu`](#target-cpu).
+The default is `None`, which LLVM translates as the `target-cpu`.
+
+This is an unstable option. Use `-Z tune-cpu=machine` to specify a value.
+
+Due to limitations in LLVM (12.0.0-git9218f92), this option is currently
+effective only for x86 targets.
+
 [option-emit]: ../command-line-arguments.md#option-emit
 [option-o-optimize]: ../command-line-arguments.md#option-o-optimize
 [profile-guided optimization]: ../profile-guided-optimization.md
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 9b2474a..ae55297 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -37,7 +37,7 @@
 `i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
 `i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
 `i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
-`x86_64-apple-darwin` | ✓ | ✓ | 64-bit OSX (10.7+, Lion+)
+`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+)
 `x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+)
 `x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
 `x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
@@ -57,10 +57,11 @@
 
 target | std | host | notes
 -------|-----|------|-------
-`aarch64-apple-ios` | ✓[^apple] |  | ARM64 iOS
+`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+)
+`aarch64-apple-ios` | ✓ |  | ARM64 iOS
 `aarch64-fuchsia` | ✓ |  | ARM64 Fuchsia
 `aarch64-linux-android` | ✓ |  | ARM64 Android
-`aarch64-pc-windows-msvc` | ✓ |  | ARM64 Windows MSVC
+`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
 `aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17)
 `aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
 `aarch64-unknown-none` | * |  | Bare ARM64, hardfloat
@@ -122,7 +123,7 @@
 `wasm32-unknown-emscripten` | ✓ |  | WebAssembly via Emscripten
 `wasm32-unknown-unknown` | ✓ |  | WebAssembly
 `wasm32-wasi` | ✓ |  | WebAssembly with WASI
-`x86_64-apple-ios` | ✓[^apple] |  | 64-bit x86 iOS
+`x86_64-apple-ios` | ✓ |  | 64-bit x86 iOS
 `x86_64-fortanix-unknown-sgx` | ✓ |  | [Fortanix ABI] for 64-bit Intel SGX
 `x86_64-fuchsia` | ✓ |  | 64-bit Fuchsia
 `x86_64-linux-android` | ✓ |  | 64-bit x86 Android
@@ -145,8 +146,7 @@
 
 target | std | host | notes
 -------|-----|------|-------
-`aarch64-apple-darwin` | ? |  | ARM64 macOS
-`aarch64-apple-tvos` | *[^apple] |  | ARM64 tvOS
+`aarch64-apple-tvos` | * |  | ARM64 tvOS
 `aarch64-unknown-cloudabi` | ✓ |  | ARM64 CloudABI
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ? |  |
@@ -158,17 +158,17 @@
 `armv4t-unknown-linux-gnueabi` | ? |  |
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
 `armv6-unknown-netbsd-eabihf` | ? |  |
-`armv7-apple-ios` | ✓[^apple] |  | ARMv7 iOS, Cortex-a8
+`armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
 `armv7-unknown-cloudabi-eabihf` | ✓ |  | ARMv7 CloudABI, hardfloat
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
 `armv7-unknown-netbsd-eabihf` | ? |  |
 `armv7-wrs-vxworks-eabihf` | ? |  |
 `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
-`armv7s-apple-ios` | ✓[^apple] |  |
+`armv7s-apple-ios` | ✓ |  |
 `avr-unknown-gnu-atmega328` | ✗ |  | AVR. Requires `-Z build-std=core`
 `hexagon-unknown-linux-musl` | ? |  |
-`i386-apple-ios` | ✓[^apple] |  | 32-bit x86 iOS
-`i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+)
+`i386-apple-ios` | ✓ |  | 32-bit x86 iOS
+`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
 `i686-unknown-cloudabi` | ✓ |  | 32-bit CloudABI
 `i686-unknown-uefi` | ? |  | 32-bit UEFI
@@ -203,8 +203,8 @@
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7a Linux with NEON, MUSL
 `thumbv4t-none-eabi` | * |  | ARMv4T T32
-`x86_64-apple-ios-macabi` | ✓[^apple] |  | Apple Catalyst
-`x86_64-apple-tvos` | *[^apple] | | x86 64-bit tvOS
+`x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst
+`x86_64-apple-tvos` | * | | x86 64-bit tvOS
 `x86_64-linux-kernel` | * |  | Linux kernel modules
 `x86_64-pc-solaris` | ? |  |
 `x86_64-pc-windows-msvc` | ✓ |  | 64-bit Windows XP support
@@ -221,4 +221,3 @@
 `x86_64-wrs-vxworks` | ? |  |
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
-[^apple]: These targets are only available on macOS.
diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md
index 93454b4..a3fa525 100644
--- a/src/doc/rustdoc/src/SUMMARY.md
+++ b/src/doc/rustdoc/src/SUMMARY.md
@@ -8,5 +8,5 @@
 - [Linking to items by name](linking-to-items-by-name.md)
 - [Lints](lints.md)
 - [Passes](passes.md)
-- [Advanced Features](advanced-features.md)
+- [Advanced features](advanced-features.md)
 - [Unstable features](unstable-features.md)
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index c9a0dff..5128ff1 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -1,8 +1,8 @@
-# Advanced Features
+# Advanced features
 
 The features listed on this page fall outside the rest of the main categories.
 
-## `#[cfg(doc)]`: Documenting platform-/feature-specific information
+## `#[cfg(doc)]`: Documenting platform-specific or feature-specific information
 
 For conditional compilation, Rustdoc treats your crate the same way the compiler does. Only things
 from the host target are available (or from the given `--target` if present), and everything else is
@@ -17,7 +17,7 @@
 This will preserve the item either when built normally on Windows, or when being documented
 anywhere.
 
-Please note that this feature is not passed to doctests.
+Please note that this `cfg` is not passed to doctests.
 
 Example:
 
@@ -33,6 +33,40 @@
 Here, the respective tokens can only be used by dependent crates on their respective platforms, but
 they will both appear in documentation.
 
+### Interactions between platform-specific docs
+
+Rustdoc does not have a magic way to compile documentation 'as-if' you'd run it once for each
+platform (such a magic wand has been called the ['holy grail of rustdoc'][#1998]). Instead,
+it sees *all* of your code at once, the same way the Rust compiler would if you passed it
+`--cfg doc`. However, Rustdoc has a trick up its sleeve to handle platform-specific code if it
+*does* receive it.
+
+To document your crate, Rustdoc only needs to know the public signature of your functions.
+In particular, it doesn't have to know how any of your functions are implemented, so it ignores
+all type errors and name resolution errors with function bodies. Note that this does *not*
+work for anything outside a function body: since Rustdoc documents your types, it has to
+know what those types are! For example, this code will work regardless of the platform:
+
+<!-- `ignore` because doc-tests are run with `rustc`, not `rustdoc` -->
+```ignore
+pub fn f() {
+    use std::os::windows::ffi::OsStrExt;
+}
+```
+
+but this will not, because the unknown type is part of the function signature:
+
+```ignore
+pub fn f() -> std::os::windows::ffi::EncodeWide<'static> {
+    unimplemented!()
+}
+```
+
+For a more realistic example of code this allows, see [the rustdoc test suite][realistic-async].
+
+[#1998]: https://github.com/rust-lang/rust/issues/1998
+[realistic-async]: https://github.com/rust-lang/rust/blob/b146000e910ccd60bdcde89363cb6aa14ecc0d95/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs
+
 ## Add aliases for an item in documentation search
 
 This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
@@ -46,3 +80,5 @@
 
 Then, when looking for it through the `rustdoc` search, if you enter "x" or
 "big", search will show the `BigX` struct first.
+
+There are some limitations on the doc alias names though: you can't use `"` or whitespace.
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
index 18010be..387d861 100644
--- a/src/doc/rustdoc/src/documentation-tests.md
+++ b/src/doc/rustdoc/src/documentation-tests.md
@@ -16,8 +16,8 @@
 The triple backticks start and end code blocks. If this were in a file named `foo.rs`,
 running `rustdoc --test foo.rs` will extract this example, and then run it as a test.
 
-Please note that by default, if no language is set for the block code, `rustdoc`
-assumes it is `Rust` code. So the following:
+Please note that by default, if no language is set for the block code, rustdoc
+assumes it is Rust code. So the following:
 
 ``````markdown
 ```rust
@@ -44,7 +44,6 @@
 
 ```rust
 let foo = "foo";
-
 assert_eq!(foo, "foo");
 ```
 
@@ -55,8 +54,9 @@
 
 In the example above, you'll note something strange: there's no `main`
 function! Forcing you to write `main` for every example, no matter how small,
-adds friction. So `rustdoc` processes your examples slightly before
-running them. Here's the full algorithm rustdoc uses to preprocess examples:
+adds friction and clutters the output. So `rustdoc` processes your examples
+slightly before running them. Here's the full algorithm `rustdoc` uses to
+preprocess examples:
 
 1. Some common `allow` attributes are inserted, including
    `unused_variables`, `unused_assignments`, `unused_mut`,
@@ -78,10 +78,12 @@
 from your example, but are important to make the tests work. Consider
 an example block that looks like this:
 
-```text
+```ignore
+/// ```
 /// /// Some documentation.
 /// # fn foo() {} // this function will be hidden
 /// println!("Hello, World!");
+/// ```
 ```
 
 It will render like this:
@@ -251,7 +253,7 @@
 This is an unfortunate consequence of the `?` operator adding an implicit
 conversion, so type inference fails because the type is not unique. Please note
 that you must write the `(())` in one sequence without intermediate whitespace
-so that rustdoc understands you want an implicit `Result`-returning function.
+so that `rustdoc` understands you want an implicit `Result`-returning function.
 
 ## Documenting macros
 
@@ -359,7 +361,7 @@
 ## Syntax reference
 
 The *exact* syntax for code blocks, including the edge cases, can be found
-in the [Fenced Code Blocks](https://spec.commonmark.org/0.28/#fenced-code-blocks)
+in the [Fenced Code Blocks](https://spec.commonmark.org/0.29/#fenced-code-blocks)
 section of the CommonMark specification.
 
 Rustdoc also accepts *indented* code blocks as an alternative to fenced
@@ -372,7 +374,7 @@
 ``````
 
 These, too, are documented in the CommonMark specification, in the
-[Indented Code Blocks](https://spec.commonmark.org/0.28/#indented-code-blocks)
+[Indented Code Blocks](https://spec.commonmark.org/0.29/#indented-code-blocks)
 section.
 
 However, it's preferable to use fenced code blocks over indented code blocks.
@@ -388,7 +390,7 @@
 collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
 docs, or to find an arbitrary private item to include it on.
 
-When compiling a crate for use in doctests (with `--test` option), rustdoc will set `cfg(doctest)`.
+When compiling a crate for use in doctests (with `--test` option), `rustdoc` will set `#[cfg(doctest)]`.
 Note that they will still link against only the public items of your crate; if you need to test
 private items, you need to write a unit test.
 
@@ -407,18 +409,18 @@
 ```
 
 Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate
-API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while rustdoc is
+API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while `rustdoc` is
 collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc,
 but is hidden from the public documentation.
 
-Another possible use of `cfg(doctest)` is to test doctests that are included in your README file
+Another possible use of `#[cfg(doctest)]` is to test doctests that are included in your README file
 without including it in your main documentation. For example, you could write this into your
 `lib.rs` to test your README as part of your doctests:
 
 ```rust,ignore
 #![feature(external_doc)]
 
-#[doc(include="../README.md")]
+#[doc(include = "../README.md")]
 #[cfg(doctest)]
 pub struct ReadmeDoctests;
 ```
diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md
index 5e46ef5..76e0439 100644
--- a/src/doc/rustdoc/src/linking-to-items-by-name.md
+++ b/src/doc/rustdoc/src/linking-to-items-by-name.md
@@ -1,6 +1,7 @@
 # Linking to items by name
 
-Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link.
+Rustdoc is capable of directly linking to other rustdoc pages using the path of
+the item as a link.
 
 For example, in the following code all of the links will link to the rustdoc page for `Bar`:
 
@@ -19,15 +20,26 @@
 /// This struct is also not [`Bar`]
 pub struct Foo4;
 
+/// This struct *is* [`Bar`]!
 pub struct Bar;
 ```
 
-You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. Backticks around the link will be stripped.
+Backticks around the link will be stripped, so ``[`Option`]`` will correctly
+link to `Option`.
+
+You can refer to anything in scope, and use paths, including `Self`, `self`,
+`super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros, respectively.
+
+You can also refer to items with generic parameters like `Vec<T>`. The link will
+resolve as if you had written ``[`Vec<T>`](Vec)``. Fully-qualified syntax (for example,
+`<Vec as IntoIterator>::into_iter()`) is [not yet supported][fqs-issue], however.
+
+[fqs-issue]: https://github.com/rust-lang/rust/issues/74563
 
 ```rust,edition2018
 use std::sync::mpsc::Receiver;
 
-/// This is an version of [`Receiver`], with support for [`std::future`].
+/// This is a version of [`Receiver<T>`] with support for [`std::future`].
 ///
 /// You can obtain a [`std::future::Future`] by calling [`Self::recv()`].
 pub struct AsyncReceiver<T> {
@@ -44,13 +56,15 @@
 You can also link to sections using URL fragment specifiers:
 
 ```rust
-/// This is a special implementation of [positional parameters]
+/// This is a special implementation of [positional parameters].
 ///
 /// [positional parameters]: std::fmt#formatting-parameters
 struct MySpecialFormatter;
 ```
 
-Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like  `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`:
+Paths in Rust have three namespaces: type, value, and macro. Item names must be
+unique within their namespace, but can overlap with items outside of their
+namespace. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `fn@`, `function@`, `mod@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`:
 
 ```rust
 /// See also: [`Foo`](struct@Foo)
@@ -62,4 +76,19 @@
 fn Foo() {}
 ```
 
-Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in.
+You can also disambiguate for functions by adding `()` after the function name,
+or for macros by adding `!` after the macro name:
+
+```rust
+/// See also: [`Foo`](struct@Foo)
+struct Bar;
+
+/// This is different from [`Foo()`]
+struct Foo {}
+
+fn Foo() {}
+```
+
+Note: Because of how `macro_rules!` macros are scoped in Rust, the intra-doc links of a `macro_rules!` macro will be resolved [relative to the crate root][#72243], as opposed to the module it is defined in.
+
+[#72243]: https://github.com/rust-lang/rust/issues/72243
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 3e632a0..cb9099c 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -4,18 +4,18 @@
 can use them like any other lints by doing this:
 
 ```rust,ignore
-#![allow(missing_docs)] // allowing the lint, no message
-#![warn(missing_docs)] // warn if there is missing docs
-#![deny(missing_docs)] // rustdoc will fail if there is missing docs
+#![allow(missing_docs)] // allows the lint, no diagnostics will be reported
+#![warn(missing_docs)] // warn if there are missing docs
+#![deny(missing_docs)] // error if there are missing docs
 ```
 
 Here is the list of the lints provided by `rustdoc`:
 
 ## broken_intra_doc_links
 
-This lint **warns by default**. This lint detects when an [intra-doc link] fails to get resolved. For example:
+This lint **warns by default**. This lint detects when an [intra-doc link] fails to be resolved. For example:
 
- [intra-doc link]: linking-to-items-by-name.html
+[intra-doc link]: linking-to-items-by-name.md
 
 ```rust
 /// I want to link to [`Nonexistent`] but it doesn't exist!
@@ -250,3 +250,38 @@
 
 In the example above, the correct form is `should_panic`. This helps detect
 typo mistakes for some common attributes.
+
+## invalid_html_tags
+
+This lint is **allowed by default** and is **nightly-only**. It detects unclosed
+or invalid HTML tags. For example:
+
+```rust
+#![warn(invalid_html_tags)]
+
+/// <h1>
+/// </script>
+pub fn foo() {}
+```
+
+Which will give:
+
+```text
+warning: unopened HTML tag `script`
+ --> foo.rs:1:1
+  |
+1 | / /// <h1>
+2 | | /// </script>
+  | |_____________^
+  |
+  = note: `#[warn(invalid_html_tags)]` on by default
+
+warning: unclosed HTML tag `h1`
+ --> foo.rs:1:1
+  |
+1 | / /// <h1>
+2 | | /// </script>
+  | |_____________^
+
+warning: 2 warnings emitted
+```
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index e4d8818..16157a4 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -43,28 +43,16 @@
 These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler
 and enabled with a `#![feature(...)]` attribute in your crate.
 
-### Documenting platform-/feature-specific information
+### `#[doc(cfg)]`: Recording what platforms or features are required for code to be present
 
-Because of the way Rustdoc documents a crate, the documentation it creates is specific to the target
-rustc compiles for. Anything that's specific to any other target is dropped via `#[cfg]` attribute
-processing early in the compilation process. However, Rustdoc has a trick up its sleeve to handle
-platform-specific code if it *does* receive it.
+You can use `#[doc(cfg(...))]` to tell Rustdoc exactly which platform items appear on.
+This has two effects:
 
-Because Rustdoc doesn't need to fully compile a crate to binary, it replaces function bodies with
-`loop {}` to prevent having to process more than necessary. This means that any code within a
-function that requires platform-specific pieces is ignored. Combined with a special attribute,
-`#[doc(cfg(...))]`, you can tell Rustdoc exactly which platform something is supposed to run on,
-ensuring that doctests are only run on the appropriate platforms.
+1. doctests will only run on the appropriate platforms, and
+2. When Rustdoc renders documentation for that item, it will be accompanied by a banner explaining
+   that the item is only available on certain platforms.
 
-The `#[doc(cfg(...))]` attribute has another effect: When Rustdoc renders documentation for that
-item, it will be accompanied by a banner explaining that the item is only available on certain
-platforms.
-
-For Rustdoc to document an item, it needs to see it, regardless of what platform it's currently
-running on. To aid this, Rustdoc sets the flag `#[cfg(doc)]` when running on your crate.
-Combining this with the target platform of a given item allows it to appear when building your crate
-normally on that platform, as well as when building documentation anywhere.
-
+`#[doc(cfg)]` is intended to be used alongside [`#[cfg(doc)]`][cfg-doc].
 For example, `#[cfg(any(windows, doc))]` will preserve the item either on Windows or during the
 documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc that
 the item is supposed to be used on Windows. For example:
@@ -81,6 +69,12 @@
 #[cfg(any(unix, doc))]
 #[doc(cfg(unix))]
 pub struct UnixToken;
+
+/// Token struct that is only available with the `serde` feature
+#[cfg(feature = "serde")]
+#[doc(cfg(feature = "serde"))]
+#[derive(serde::Deserialize)]
+pub struct SerdeToken;
 ```
 
 In this sample, the tokens will only appear on their respective platforms, but they will both appear
@@ -90,6 +84,7 @@
 `#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable
 Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
 
+[cfg-doc]: ./advanced-features.md
 [unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
 [issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
 
diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md
new file mode 100644
index 0000000..878c894
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md
@@ -0,0 +1,31 @@
+# `codegen-backend`
+
+The tracking issue for this feature is: [#77933](https://github.com/rust-lang/rust/issues/77933).
+
+------------------------
+
+This feature allows you to specify a path to a dynamic library to use as rustc's
+code generation backend at runtime.
+
+Set the `-Zcodegen-backend=<path>` compiler flag to specify the location of the
+backend. The library must be of crate type `dylib` and must contain a function
+named `__rustc_codegen_backend` with a signature of `fn() -> Box<dyn rustc_codegen_ssa::traits::CodegenBackend>`.
+
+## Example
+See also the [`hotplug_codegen_backend`](https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/hotplug_codegen_backend) test
+for a full example.
+
+```rust,ignore
+use rustc_codegen_ssa::traits::CodegenBackend;
+
+struct MyBackend;
+
+impl CodegenBackend for MyBackend {
+   // Implement codegen methods
+}
+
+#[no_mangle]
+pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
+    Box::new(MyBackend)
+}
+```
diff --git a/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md b/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md
new file mode 100644
index 0000000..8e46e22
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md
@@ -0,0 +1,8 @@
+# `unsound-mir-opts`
+
+--------------------
+
+The `-Zunsound-mir-opts` compiler flag enables [MIR optimization passes] which can cause unsound behavior.
+This flag should only be used by MIR optimization tests in the rustc test suite.
+
+[MIR optimization passes]: https://rustc-dev-guide.rust-lang.org/mir/optimizations.html
diff --git a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md
new file mode 100644
index 0000000..338fbc4
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md
@@ -0,0 +1,81 @@
+# `cmse_nonsecure_entry`
+
+The tracking issue for this feature is: [#75835]
+
+[#75835]: https://github.com/rust-lang/rust/issues/75835
+
+------------------------
+
+The [TrustZone-M
+feature](https://developer.arm.com/documentation/100690/latest/) is available
+for targets with the Armv8-M architecture profile (`thumbv8m` in their target
+name).
+LLVM, the Rust compiler and the linker are providing
+[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the
+TrustZone-M feature.
+
+One of the things provided, with this unstable feature, is the
+`cmse_nonsecure_entry` attribute.  This attribute marks a Secure function as an
+entry function (see [section
+5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details).
+With this attribute, the compiler will do the following:
+* add a special symbol on the function which is the `__acle_se_` prefix and the
+  standard function name
+* constrain the number of parameters to avoid using the Non-Secure stack
+* before returning from the function, clear registers that might contain Secure
+  information
+* use the `BXNS` instruction to return
+
+Because the stack can not be used to pass parameters, there will be compilation
+errors if:
+* the total size of all parameters is too big (for example more than four 32
+  bits integers)
+* the entry function is not using a C ABI
+
+The special symbol `__acle_se_` will be used by the linker to generate a secure
+gateway veneer.
+
+<!-- NOTE(ignore) this example is specific to thumbv8m targets -->
+
+``` rust,ignore
+#![feature(cmse_nonsecure_entry)]
+
+#[no_mangle]
+#[cmse_nonsecure_entry]
+pub extern "C" fn entry_function(input: u32) -> u32 {
+    input + 6
+}
+```
+
+``` text
+$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs
+$ arm-none-eabi-objdump -D function.o
+
+00000000 <entry_function>:
+   0:   b580            push    {r7, lr}
+   2:   466f            mov     r7, sp
+   4:   b082            sub     sp, #8
+   6:   9001            str     r0, [sp, #4]
+   8:   1d81            adds    r1, r0, #6
+   a:   460a            mov     r2, r1
+   c:   4281            cmp     r1, r0
+   e:   9200            str     r2, [sp, #0]
+  10:   d30b            bcc.n   2a <entry_function+0x2a>
+  12:   e7ff            b.n     14 <entry_function+0x14>
+  14:   9800            ldr     r0, [sp, #0]
+  16:   b002            add     sp, #8
+  18:   e8bd 4080       ldmia.w sp!, {r7, lr}
+  1c:   4671            mov     r1, lr
+  1e:   4672            mov     r2, lr
+  20:   4673            mov     r3, lr
+  22:   46f4            mov     ip, lr
+  24:   f38e 8800       msr     CPSR_f, lr
+  28:   4774            bxns    lr
+  2a:   f240 0000       movw    r0, #0
+  2e:   f2c0 0000       movt    r0, #0
+  32:   f240 0200       movw    r2, #0
+  36:   f2c0 0200       movt    r2, #0
+  3a:   211c            movs    r1, #28
+  3c:   f7ff fffe       bl      0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E>
+  40:   defe            udf     #254    ; 0xfe
+```
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index 9bed06d..6e4e1f7 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -27,7 +27,7 @@
 - RISC-V
 - NVPTX
 - Hexagon
-- MIPS32
+- MIPS32r2 and MIPS64r2
 
 ## Basic usage
 
@@ -410,7 +410,7 @@
 operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
 reg_operand := dir_spec "(" reg_spec ")" operand_expr
 operand := reg_operand / "const" const_expr / "sym" path
-option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax"
+option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax"
 options := "options(" option *["," option] [","] ")"
 asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
 ```
@@ -513,8 +513,8 @@
 | ARM | `qreg` | `q[0-15]` | `w` |
 | ARM | `qreg_low8` | `q[0-7]` | `t` |
 | ARM | `qreg_low4` | `q[0-3]` | `x` |
-| MIPS32 | `reg` | `$[2-25]` | `r` |
-| MIPS32 | `freg` | `$f[0-31]` | `f` |
+| MIPS | `reg` | `$[2-25]` | `r` |
+| MIPS | `freg` | `$f[0-31]` | `f` |
 | NVPTX | `reg16` | None\* | `h` |
 | NVPTX | `reg32` | None\* | `r` |
 | NVPTX | `reg64` | None\* | `l` |
@@ -551,7 +551,9 @@
 | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
 | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
 | MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
-| MIPS32 | `freg` | None | `f32` |
+| MIPS32 | `freg` | None | `f32`, `f64` |
+| MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
+| MIPS64 | `freg` | None | `f32`, `f64` |
 | NVPTX | `reg16` | None | `i8`, `i16` |
 | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
 | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
@@ -600,7 +602,6 @@
 | ARM | `r13` | `sp` |
 | ARM | `r14` | `lr` |
 | ARM | `r15` | `pc` |
-| MIPS32 | `$[2-25]` | Please [see the Wikipedia page][mips-regs] |
 | RISC-V | `x0` | `zero` |
 | RISC-V | `x1` | `ra` |
 | RISC-V | `x2` | `sp` |
@@ -621,8 +622,6 @@
 | Hexagon | `r30` | `fr` |
 | Hexagon | `r31` | `lr` |
 
-[mips-regs]: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File#Registers
-
 Some registers cannot be used for input or output operands:
 
 | Architecture | Unsupported register | Reason |
@@ -637,11 +636,11 @@
 | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
 | AArch64 | `xzr` | This is a constant zero register which can't be modified. |
 | ARM | `pc` | This is the program counter, not a real register. |
-| MIPS32 | `$0` or `$zero` | This is a constant zero register which can't be modified. |
-| MIPS32 | `$1` or `$at` | Reserved for assembler. |
-| MIPS32 | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
-| MIPS32 | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
-| MIPS32 | `$ra` | Return address cannot be used as inputs or outputs. |
+| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
+| MIPS | `$1` or `$at` | Reserved for assembler. |
+| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
+| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
+| MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
 | RISC-V | `x0` | This is a constant zero register which can't be modified. |
 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
 | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
@@ -689,8 +688,8 @@
 | ARM | `dreg` | None | `d0` | `P` |
 | ARM | `qreg` | None | `q0` | `q` |
 | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
-| MIPS32 | `reg` | None | `$2` | None |
-| MIPS32 | `freg` | None | `$f0` | None |
+| MIPS | `reg` | None | `$2` | None |
+| MIPS | `freg` | None | `$f0` | None |
 | NVPTX | `reg16` | None | `rs0` | None |
 | NVPTX | `reg32` | None | `r0` | None |
 | NVPTX | `reg64` | None | `rd0` | None |
diff --git a/src/doc/unstable-book/src/library-features/default-free-fn.md b/src/doc/unstable-book/src/library-features/default-free-fn.md
index 5dff73a..d40a27d 100644
--- a/src/doc/unstable-book/src/library-features/default-free-fn.md
+++ b/src/doc/unstable-book/src/library-features/default-free-fn.md
@@ -10,6 +10,8 @@
 just forwards to [`Default::default()`], but may remove repetition of the word
 "default" from the call site.
 
+[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default
+
 Here is an example:
 
 ```rust
diff --git a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md
new file mode 100644
index 0000000..0e95d5d
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md
@@ -0,0 +1,10 @@
+# `range_bounds_assert_len`
+
+The tracking issue for this feature is: [#76393]
+
+------------------------
+
+This adds [`RangeBounds::assert_len`].
+
+[#76393]: https://github.com/rust-lang/rust/issues/76393
+[`RangeBounds::assert_len`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.assert_len
diff --git a/src/doc/unstable-book/src/library-features/slice-check-range.md b/src/doc/unstable-book/src/library-features/slice-check-range.md
deleted file mode 100644
index 83e5738..0000000
--- a/src/doc/unstable-book/src/library-features/slice-check-range.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# `slice_check_range`
-
-The tracking issue for this feature is: [#76393]
-
-------------------------
-
-This adds [`slice::check_range`].
-
-[#76393]: https://github.com/rust-lang/rust/issues/76393
-[`slice::check_range`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.check_range
diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py
index bae51e6..eec3027 100644
--- a/src/etc/gdb_providers.py
+++ b/src/etc/gdb_providers.py
@@ -207,30 +207,43 @@
         yield "borrow", self.borrow
 
 
-# Yield each key (and optionally value) from a BoxedNode.
-def children_of_node(boxed_node, height, want_values):
+# Yields children (in a provider's sense of the word) for a tree headed by a BoxedNode.
+# In particular, yields each key/value pair in the node and in any child nodes.
+def children_of_node(boxed_node, height):
     def cast_to_internal(node):
-        internal_type_name = str(node.type.target()).replace("LeafNode", "InternalNode", 1)
+        internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1)
         internal_type = lookup_type(internal_type_name)
         return node.cast(internal_type.pointer())
 
     node_ptr = unwrap_unique_or_non_null(boxed_node["ptr"])
-    node_ptr = cast_to_internal(node_ptr) if height > 0 else node_ptr
-    leaf = node_ptr["data"] if height > 0 else node_ptr.dereference()
+    leaf = node_ptr.dereference()
     keys = leaf["keys"]
-    values = leaf["vals"]
+    vals = leaf["vals"]
+    edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None
     length = int(leaf["len"])
 
     for i in xrange(0, length + 1):
         if height > 0:
-            child_ptr = node_ptr["edges"][i]["value"]["value"]
-            for child in children_of_node(child_ptr, height - 1, want_values):
+            boxed_child_node = edges[i]["value"]["value"]
+            for child in children_of_node(boxed_child_node, height - 1):
                 yield child
         if i < length:
-            if want_values:
-                yield keys[i]["value"]["value"], values[i]["value"]["value"]
-            else:
-                yield keys[i]["value"]["value"]
+            # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
+            key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else "()"
+            val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else "()"
+            yield key, val
+
+
+# Yields children for a BTreeMap.
+def children_of_map(map):
+    if map["length"] > 0:
+        root = map["root"]
+        if root.type.name.startswith("core::option::Option<"):
+            root = root.cast(gdb.lookup_type(root.type.name[21:-1]))
+        boxed_root_node = root["node"]
+        height = root["height"]
+        for child in children_of_node(boxed_root_node, height):
+            yield child
 
 
 class StdBTreeSetProvider:
@@ -242,15 +255,8 @@
 
     def children(self):
         inner_map = self.valobj["map"]
-        if inner_map["length"] > 0:
-            root = inner_map["root"]
-            if "core::option::Option<" in root.type.name:
-                type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1]
-                root = root.cast(gdb.lookup_type(type_name))
-
-            node_ptr = root["node"]
-            for i, child in enumerate(children_of_node(node_ptr, root["height"], False)):
-                yield "[{}]".format(i), child
+        for i, (child, _) in enumerate(children_of_map(inner_map)):
+            yield "[{}]".format(i), child
 
     @staticmethod
     def display_hint():
@@ -265,16 +271,9 @@
         return "BTreeMap(size={})".format(self.valobj["length"])
 
     def children(self):
-        if self.valobj["length"] > 0:
-            root = self.valobj["root"]
-            if "core::option::Option<" in root.type.name:
-                type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1]
-                root = root.cast(gdb.lookup_type(type_name))
-
-            node_ptr = root["node"]
-            for i, child in enumerate(children_of_node(node_ptr, root["height"], True)):
-                yield "key{}".format(i), child[0]
-                yield "val{}".format(i), child[1]
+        for i, (key, val) in enumerate(children_of_map(self.valobj)):
+            yield "key{}".format(i), key
+            yield "val{}".format(i), val
 
     @staticmethod
     def display_hint():
diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 979f2fa..b8e6c6c 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -1,18 +1,18 @@
-type synthetic add -l lldb_lookup.synthetic_lookup -x \".*\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)String$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^&str$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^&\\[.+\\]$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(std::ffi::([a-z_]+::)+)OsString$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)Vec<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)VecDeque<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)BTreeSet<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)BTreeMap<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(std::collections::([a-z_]+::)+)HashMap<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(std::collections::([a-z_]+::)+)HashSet<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)Rc<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)Arc<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)Cell<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)Ref<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)RefMut<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)RefCell<.+>$\" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&str$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&\\[.+\\]$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
 type category enable Rust
diff --git a/src/etc/pre-commit.sh b/src/etc/pre-commit.sh
new file mode 100755
index 0000000..70b4e9d
--- /dev/null
+++ b/src/etc/pre-commit.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+#
+# Call `tidy --bless` before each commit
+# Copy this scripts to .git/hooks to activate,
+# and remove it from .git/hooks to deactivate.
+#
+
+set -Eeuo pipefail
+
+# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
+unset GIT_DIR
+ROOT_DIR="$(git rev-parse --show-toplevel)"
+COMMAND="$ROOT_DIR/x.py test tidy --bless"
+
+if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
+  COMMAND="python $COMMAND"
+fi
+
+echo "Running pre-commit script '$COMMAND'"
+
+cd "$ROOT_DIR"
+
+$COMMAND
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 1ea1a09..f39b53f 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -315,12 +315,13 @@
         tcx: TyCtxt<'tcx>,
         pred: ty::Predicate<'tcx>,
     ) -> FxHashSet<GenericParamDef> {
-        let regions = match pred.skip_binders() {
+        let bound_predicate = pred.bound_atom();
+        let regions = match bound_predicate.skip_binder() {
             ty::PredicateAtom::Trait(poly_trait_pred, _) => {
-                tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(poly_trait_pred))
+                tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred))
             }
             ty::PredicateAtom::Projection(poly_proj_pred) => {
-                tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(poly_proj_pred))
+                tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred))
             }
             _ => return FxHashSet::default(),
         };
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index c039b18..b659f3e 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -201,6 +201,37 @@
             _ => false,
         }
     }
+
+    /// Attempt to simplify this cfg by assuming that `assume` is already known to be true, will
+    /// return `None` if simplification managed to completely eliminate any requirements from this
+    /// `Cfg`.
+    ///
+    /// See `tests::test_simplify_with` for examples.
+    pub(crate) fn simplify_with(&self, assume: &Cfg) -> Option<Cfg> {
+        if self == assume {
+            return None;
+        }
+
+        if let Cfg::All(a) = self {
+            let mut sub_cfgs: Vec<Cfg> = if let Cfg::All(b) = assume {
+                a.iter().filter(|a| !b.contains(a)).cloned().collect()
+            } else {
+                a.iter().filter(|&a| a != assume).cloned().collect()
+            };
+            let len = sub_cfgs.len();
+            return match len {
+                0 => None,
+                1 => sub_cfgs.pop(),
+                _ => Some(Cfg::All(sub_cfgs)),
+            };
+        } else if let Cfg::All(b) = assume {
+            if b.contains(self) {
+                return None;
+            }
+        }
+
+        Some(self.clone())
+    }
 }
 
 impl ops::Not for Cfg {
diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs
index 794a7bc..3a78269 100644
--- a/src/librustdoc/clean/cfg/tests.rs
+++ b/src/librustdoc/clean/cfg/tests.rs
@@ -433,3 +433,39 @@
         );
     })
 }
+
+#[test]
+fn test_simplify_with() {
+    // This is a tiny subset of things that could be simplified, but it likely covers 90% of
+    // real world usecases well.
+    with_default_session_globals(|| {
+        let foo = word_cfg("foo");
+        let bar = word_cfg("bar");
+        let baz = word_cfg("baz");
+        let quux = word_cfg("quux");
+
+        let foobar = Cfg::All(vec![foo.clone(), bar.clone()]);
+        let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]);
+        let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]);
+        let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]);
+
+        // Unrelated cfgs don't affect each other
+        assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo));
+        assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar));
+
+        // Identical cfgs are eliminated
+        assert_eq!(foo.simplify_with(&foo), None);
+        assert_eq!(foobar.simplify_with(&foobar), None);
+
+        // Multiple cfgs eliminate a single assumed cfg
+        assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar));
+        assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo));
+
+        // A single cfg is eliminated by multiple assumed cfg containing it
+        assert_eq!(foo.simplify_with(&foobar), None);
+
+        // Multiple cfgs eliminate the matching subset of multiple assumed cfg
+        assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo));
+        assert_eq!(foobar.simplify_with(&foobarbaz), None);
+    });
+}
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 31e8c32..6267b02 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -15,7 +15,7 @@
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
-use crate::clean::{self, GetDefId, ToSource, TypeKind};
+use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind};
 use crate::core::DocContext;
 use crate::doctree;
 
@@ -35,8 +35,11 @@
 ///
 /// The returned value is `None` if the definition could not be inlined,
 /// and `Some` of a vector of items if it was successfully expanded.
+///
+/// `parent_module` refers to the parent of the *re-export*, not the original item.
 pub fn try_inline(
     cx: &DocContext<'_>,
+    parent_module: DefId,
     res: Res,
     name: Symbol,
     attrs: Option<Attrs<'_>>,
@@ -48,12 +51,13 @@
     }
     let mut ret = Vec::new();
 
+    debug!("attrs={:?}", attrs);
     let attrs_clone = attrs;
 
     let inner = match res {
         Res::Def(DefKind::Trait, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Trait);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::TraitItem(build_external_trait(cx, did))
         }
         Res::Def(DefKind::Fn, did) => {
@@ -62,27 +66,27 @@
         }
         Res::Def(DefKind::Struct, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Struct);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::StructItem(build_struct(cx, did))
         }
         Res::Def(DefKind::Union, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Union);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::UnionItem(build_union(cx, did))
         }
         Res::Def(DefKind::TyAlias, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Typedef);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::TypedefItem(build_type_alias(cx, did), false)
         }
         Res::Def(DefKind::Enum, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Enum);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::EnumItem(build_enum(cx, did))
         }
         Res::Def(DefKind::ForeignTy, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Foreign);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::ForeignTypeItem
         }
         // Never inline enum variants but leave them shown as re-exports.
@@ -117,7 +121,7 @@
     };
 
     let target_attrs = load_attrs(cx, did);
-    let attrs = merge_attrs(cx, target_attrs, attrs_clone);
+    let attrs = merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone);
 
     cx.renderinfo.borrow_mut().inlined.insert(did);
     ret.push(clean::Item {
@@ -126,7 +130,7 @@
         attrs,
         inner,
         visibility: clean::Public,
-        stability: cx.tcx.lookup_stability(did).clean(cx),
+        stability: cx.tcx.lookup_stability(did).cloned(),
         deprecation: cx.tcx.lookup_deprecation(did).clean(cx),
         def_id: did,
     });
@@ -290,38 +294,53 @@
     }
 }
 
-pub fn build_impls(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>) -> Vec<clean::Item> {
+/// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
+pub fn build_impls(
+    cx: &DocContext<'_>,
+    parent_module: Option<DefId>,
+    did: DefId,
+    attrs: Option<Attrs<'_>>,
+) -> Vec<clean::Item> {
     let tcx = cx.tcx;
     let mut impls = Vec::new();
 
+    // for each implementation of an item represented by `did`, build the clean::Item for that impl
     for &did in tcx.inherent_impls(did).iter() {
-        build_impl(cx, did, attrs, &mut impls);
+        build_impl(cx, parent_module, did, attrs, &mut impls);
     }
 
     impls
 }
 
+/// `parent_module` refers to the parent of the re-export, not the original item
 fn merge_attrs(
     cx: &DocContext<'_>,
-    attrs: Attrs<'_>,
-    other_attrs: Option<Attrs<'_>>,
+    parent_module: Option<DefId>,
+    old_attrs: Attrs<'_>,
+    new_attrs: Option<Attrs<'_>>,
 ) -> clean::Attributes {
     // NOTE: If we have additional attributes (from a re-export),
     // always insert them first. This ensure that re-export
     // doc comments show up before the original doc comments
     // when we render them.
-    let merged_attrs = if let Some(inner) = other_attrs {
-        let mut both = inner.to_vec();
-        both.extend_from_slice(attrs);
-        both
+    if let Some(inner) = new_attrs {
+        if let Some(new_id) = parent_module {
+            let diag = cx.sess().diagnostic();
+            Attributes::from_ast(diag, old_attrs, Some((inner, new_id)))
+        } else {
+            let mut both = inner.to_vec();
+            both.extend_from_slice(old_attrs);
+            both.clean(cx)
+        }
     } else {
-        attrs.to_vec()
-    };
-    merged_attrs.clean(cx)
+        old_attrs.clean(cx)
+    }
 }
 
+/// Builds a specific implementation of a type. The `did` could be a type method or trait method.
 pub fn build_impl(
     cx: &DocContext<'_>,
+    parent_module: impl Into<Option<DefId>>,
     did: DefId,
     attrs: Option<Attrs<'_>>,
     ret: &mut Vec<clean::Item>,
@@ -330,7 +349,8 @@
         return;
     }
 
-    let attrs = merge_attrs(cx, load_attrs(cx, did), attrs);
+    let attrs = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
+    debug!("merged_attrs={:?}", attrs);
 
     let tcx = cx.tcx;
     let associated_trait = tcx.impl_trait_ref(did);
@@ -441,7 +461,7 @@
         name: None,
         attrs,
         visibility: clean::Inherited,
-        stability: tcx.lookup_stability(did).clean(cx),
+        stability: tcx.lookup_stability(did).cloned(),
         deprecation: tcx.lookup_deprecation(did).clean(cx),
         def_id: did,
     });
@@ -478,7 +498,7 @@
                         visibility: clean::Public,
                         stability: None,
                         deprecation: None,
-                        inner: clean::ImportItem(clean::Import::Simple(
+                        inner: clean::ImportItem(clean::Import::new_simple(
                             item.ident.to_string(),
                             clean::ImportSource {
                                 path: clean::Path {
@@ -494,9 +514,12 @@
                                 },
                                 did: None,
                             },
+                            true,
                         )),
                     });
-                } else if let Some(i) = try_inline(cx, item.res, item.ident.name, None, visited) {
+                } else if let Some(i) =
+                    try_inline(cx, did, item.res, item.ident.name, None, visited)
+                {
                     items.extend(i)
                 }
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 788bb5e..bfc7470 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -19,14 +19,13 @@
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::bug;
 use rustc_middle::middle::resolve_lifetime as rl;
-use rustc_middle::middle::stability;
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
 use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn};
-use rustc_span::hygiene::MacroKind;
+use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{self, Pos};
+use rustc_span::{self, ExpnKind, Pos};
 use rustc_typeck::hir_ty_to_ty;
 
 use std::collections::hash_map::Entry;
@@ -274,7 +273,7 @@
             attrs,
             source: span.clean(cx),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             inner: ModuleItem(Module { is_crate: self.is_crate, items }),
@@ -284,7 +283,7 @@
 
 impl Clean<Attributes> for [ast::Attribute] {
     fn clean(&self, cx: &DocContext<'_>) -> Attributes {
-        Attributes::from_ast(cx.sess().diagnostic(), self)
+        Attributes::from_ast(cx.sess().diagnostic(), self, None)
     }
 }
 
@@ -914,7 +913,7 @@
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: did.to_def_id(),
             inner: FunctionItem(Function {
@@ -1023,7 +1022,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: TraitItem(Trait {
                 auto: self.is_auto.clean(cx),
@@ -1047,7 +1046,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: TraitAliasItem(TraitAlias {
                 generics: self.generics.clean(cx),
@@ -1268,13 +1267,10 @@
             ty::AssocKind::Type => {
                 let my_name = self.ident.name.clean(cx);
 
-                if let ty::TraitContainer(did) = self.container {
-                    // When loading a cross-crate associated type, the bounds for this type
-                    // are actually located on the trait/impl itself, so we need to load
-                    // all of the generics from there and then look for bounds that are
-                    // applied to this associated type in question.
-                    let predicates = cx.tcx.explicit_predicates_of(did);
-                    let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+                if let ty::TraitContainer(_) = self.container {
+                    let bounds = cx.tcx.explicit_item_bounds(self.def_id);
+                    let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
+                    let generics = (cx.tcx.generics_of(self.def_id), predicates).clean(cx);
                     let mut bounds = generics
                         .where_predicates
                         .iter()
@@ -1567,7 +1563,7 @@
             ty::Str => Primitive(PrimitiveType::Str),
             ty::Slice(ty) => Slice(box ty.clean(cx)),
             ty::Array(ty, n) => {
-                let mut n = cx.tcx.lift(&n).expect("array lift failed");
+                let mut n = cx.tcx.lift(n).expect("array lift failed");
                 n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
                 let n = print_const(cx, n);
                 Array(box ty.clean(cx), n)
@@ -1577,7 +1573,7 @@
                 BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) }
             }
             ty::FnDef(..) | ty::FnPtr(_) => {
-                let ty = cx.tcx.lift(self).expect("FnPtr lift failed");
+                let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
                 let sig = ty.fn_sig(cx.tcx);
                 let def_id = DefId::local(CRATE_DEF_INDEX);
                 BareFunction(box BareFunctionDecl {
@@ -1678,19 +1674,25 @@
 
             ty::Opaque(def_id, substs) => {
                 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
-                // by looking up the projections associated with the def_id.
-                let predicates_of = cx.tcx.explicit_predicates_of(def_id);
-                let substs = cx.tcx.lift(&substs).expect("Opaque lift failed");
-                let bounds = predicates_of.instantiate(cx.tcx, substs);
+                // by looking up the bounds associated with the def_id.
+                let substs = cx.tcx.lift(substs).expect("Opaque lift failed");
+                let bounds = cx
+                    .tcx
+                    .explicit_item_bounds(def_id)
+                    .iter()
+                    .map(|(bound, _)| bound.subst(cx.tcx, substs))
+                    .collect::<Vec<_>>();
                 let mut regions = vec![];
                 let mut has_sized = false;
                 let mut bounds = bounds
-                    .predicates
                     .iter()
-                    .filter_map(|predicate| {
+                    .filter_map(|bound| {
                         // Note: The substs of opaque types can contain unbound variables,
                         // meaning that we have to use `ignore_quantifiers_with_unbound_vars` here.
-                        let trait_ref = match predicate.bound_atom(cx.tcx).skip_binder() {
+                        let trait_ref = match bound
+                            .bound_atom_with_opt_escaping(cx.tcx)
+                            .skip_binder()
+                        {
                             ty::PredicateAtom::Trait(tr, _constness) => {
                                 ty::Binder::bind(tr.trait_ref)
                             }
@@ -1711,11 +1713,10 @@
                         }
 
                         let bounds: Vec<_> = bounds
-                            .predicates
                             .iter()
-                            .filter_map(|pred| {
+                            .filter_map(|bound| {
                                 if let ty::PredicateAtom::Projection(proj) =
-                                    pred.bound_atom(cx.tcx).skip_binder()
+                                    bound.bound_atom_with_opt_escaping(cx.tcx).skip_binder()
                                 {
                                     if proj.projection_ty.trait_ref(cx.tcx)
                                         == trait_ref.skip_binder()
@@ -1833,7 +1834,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: StructItem(Struct {
                 struct_type: self.struct_type,
@@ -1853,7 +1854,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: UnionItem(Union {
                 struct_type: self.struct_type,
@@ -1883,7 +1884,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: EnumItem(Enum {
                 variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
@@ -1901,7 +1902,7 @@
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: Inherited,
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             inner: VariantItem(Variant { kind: self.def.clean(cx) }),
@@ -2050,7 +2051,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
         }
@@ -2065,15 +2066,12 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
-            inner: OpaqueTyItem(
-                OpaqueTy {
-                    bounds: self.opaque_ty.bounds.clean(cx),
-                    generics: self.opaque_ty.generics.clean(cx),
-                },
-                false,
-            ),
+            inner: OpaqueTyItem(OpaqueTy {
+                bounds: self.opaque_ty.bounds.clean(cx),
+                generics: self.opaque_ty.generics.clean(cx),
+            }),
         }
     }
 }
@@ -2096,7 +2094,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: StaticItem(Static {
                 type_: self.type_.clean(cx),
@@ -2117,7 +2115,7 @@
             source: self.span.clean(cx),
             def_id: def_id.to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: ConstantItem(Constant {
                 type_: self.type_.clean(cx),
@@ -2171,7 +2169,7 @@
             source: self.span.clean(cx),
             def_id: def_id.to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: ImplItem(Impl {
                 unsafety: self.unsafety,
@@ -2209,9 +2207,14 @@
 
             let res = Res::Def(DefKind::Mod, DefId { krate: self.cnum, index: CRATE_DEF_INDEX });
 
-            if let Some(items) =
-                inline::try_inline(cx, res, self.name, Some(self.attrs), &mut visited)
-            {
+            if let Some(items) = inline::try_inline(
+                cx,
+                cx.tcx.parent_module(self.hir_id).to_def_id(),
+                res,
+                self.name,
+                Some(self.attrs),
+                &mut visited,
+            ) {
                 return items;
             }
         }
@@ -2231,6 +2234,13 @@
 
 impl Clean<Vec<Item>> for doctree::Import<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
+        // We need this comparison because some imports (for std types for example)
+        // are "inserted" as well but directly by the compiler and they should not be
+        // taken into account.
+        if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
+            return Vec::new();
+        }
+
         // We consider inlining the documentation of `pub use` statements, but we
         // forcefully don't inline if this is not public or if the
         // #[doc(no_inline)] attribute is present.
@@ -2257,8 +2267,7 @@
                     return items;
                 }
             }
-
-            Import::Glob(resolve_use_source(cx, path))
+            Import::new_glob(resolve_use_source(cx, path), true)
         } else {
             let name = self.name;
             if !please_inline {
@@ -2272,13 +2281,33 @@
             }
             if !denied {
                 let mut visited = FxHashSet::default();
-                if let Some(items) =
-                    inline::try_inline(cx, path.res, name, Some(self.attrs), &mut visited)
-                {
+
+                if let Some(mut items) = inline::try_inline(
+                    cx,
+                    cx.tcx.parent_module(self.id).to_def_id(),
+                    path.res,
+                    name,
+                    Some(self.attrs),
+                    &mut visited,
+                ) {
+                    items.push(Item {
+                        name: None,
+                        attrs: self.attrs.clean(cx),
+                        source: self.span.clean(cx),
+                        def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
+                        visibility: self.vis.clean(cx),
+                        stability: None,
+                        deprecation: None,
+                        inner: ImportItem(Import::new_simple(
+                            self.name.clean(cx),
+                            resolve_use_source(cx, path),
+                            false,
+                        )),
+                    });
                     return items;
                 }
             }
-            Import::Simple(name.clean(cx), resolve_use_source(cx, path))
+            Import::new_simple(name.clean(cx), resolve_use_source(cx, path), true)
         };
 
         vec![Item {
@@ -2329,7 +2358,7 @@
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner,
         }
@@ -2344,7 +2373,7 @@
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: Public,
-            stability: cx.stability(self.hid).clean(cx),
+            stability: cx.stability(self.hid),
             deprecation: cx.deprecation(self.hid).clean(cx),
             def_id: self.def_id,
             inner: MacroItem(Macro {
@@ -2369,7 +2398,7 @@
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: Public,
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             inner: ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }),
@@ -2377,27 +2406,6 @@
     }
 }
 
-impl Clean<Stability> for attr::Stability {
-    fn clean(&self, _: &DocContext<'_>) -> Stability {
-        Stability {
-            level: stability::StabilityLevel::from_attr_level(&self.level),
-            feature: self.feature.to_string(),
-            since: match self.level {
-                attr::Stable { ref since } => since.to_string(),
-                _ => String::new(),
-            },
-            unstable_reason: match self.level {
-                attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
-                _ => None,
-            },
-            issue: match self.level {
-                attr::Unstable { issue, .. } => issue,
-                _ => None,
-            },
-        }
-    }
-}
-
 impl Clean<Deprecation> for attr::Deprecation {
     fn clean(&self, _: &DocContext<'_>) -> Deprecation {
         Deprecation {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 223fda8..32b3f69 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -4,7 +4,6 @@
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::lazy::SyncOnceCell as OnceCell;
-use std::num::NonZeroU32;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::{slice, vec};
@@ -12,18 +11,20 @@
 use rustc_ast::attr;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_ast::{self as ast, AttrStyle};
+use rustc_ast::{FloatTy, IntTy, UintTy};
+use rustc_attr::{Stability, StabilityLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_feature::UnstableFeatures;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Mutability;
 use rustc_index::vec::IndexVec;
-use rustc_middle::middle::stability;
 use rustc_middle::ty::{AssocKind, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DUMMY_SP;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr};
 use rustc_span::{self, FileName};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
@@ -177,6 +178,7 @@
     pub fn is_stripped(&self) -> bool {
         match self.inner {
             StrippedItem(..) => true,
+            ImportItem(ref i) => !i.should_be_displayed,
             _ => false,
         }
     }
@@ -195,7 +197,7 @@
         self.stability.as_ref().and_then(|ref s| {
             let mut classes = Vec::with_capacity(2);
 
-            if s.level == stability::Unstable {
+            if s.level.is_unstable() {
                 classes.push("unstable");
             }
 
@@ -208,8 +210,11 @@
         })
     }
 
-    pub fn stable_since(&self) -> Option<&str> {
-        self.stability.as_ref().map(|s| &s.since[..])
+    pub fn stable_since(&self) -> Option<SymbolStr> {
+        match self.stability?.level {
+            StabilityLevel::Stable { since, .. } => Some(since.as_str()),
+            StabilityLevel::Unstable { .. } => None,
+        }
     }
 
     pub fn is_non_exhaustive(&self) -> bool {
@@ -252,7 +257,7 @@
     FunctionItem(Function),
     ModuleItem(Module),
     TypedefItem(Typedef, bool /* is associated type */),
-    OpaqueTyItem(OpaqueTy, bool /* is associated type */),
+    OpaqueTyItem(OpaqueTy),
     StaticItem(Static),
     ConstantItem(Constant),
     TraitItem(Trait),
@@ -370,32 +375,27 @@
 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
 /// kept separate because of issue #42760.
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum DocFragment {
-    /// A doc fragment created from a `///` or `//!` doc comment.
-    SugaredDoc(usize, rustc_span::Span, String),
-    /// A doc fragment created from a "raw" `#[doc=""]` attribute.
-    RawDoc(usize, rustc_span::Span, String),
-    /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
-    /// given filename and the file contents.
-    Include(usize, rustc_span::Span, String, String),
+pub struct DocFragment {
+    pub line: usize,
+    pub span: rustc_span::Span,
+    /// The module this doc-comment came from.
+    ///
+    /// This allows distinguishing between the original documentation and a pub re-export.
+    /// If it is `None`, the item was not re-exported.
+    pub parent_module: Option<DefId>,
+    pub doc: String,
+    pub kind: DocFragmentKind,
 }
 
-impl DocFragment {
-    pub fn as_str(&self) -> &str {
-        match *self {
-            DocFragment::SugaredDoc(_, _, ref s) => &s[..],
-            DocFragment::RawDoc(_, _, ref s) => &s[..],
-            DocFragment::Include(_, _, _, ref s) => &s[..],
-        }
-    }
-
-    pub fn span(&self) -> rustc_span::Span {
-        match *self {
-            DocFragment::SugaredDoc(_, span, _)
-            | DocFragment::RawDoc(_, span, _)
-            | DocFragment::Include(_, span, _, _) => span,
-        }
-    }
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum DocFragmentKind {
+    /// A doc fragment created from a `///` or `//!` doc comment.
+    SugaredDoc,
+    /// A doc fragment created from a "raw" `#[doc=""]` attribute.
+    RawDoc,
+    /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
+    /// given filename and the file contents.
+    Include { filename: String },
 }
 
 impl<'a> FromIterator<&'a DocFragment> for String {
@@ -407,12 +407,7 @@
             if !acc.is_empty() {
                 acc.push('\n');
             }
-            match *frag {
-                DocFragment::SugaredDoc(_, _, ref docs)
-                | DocFragment::RawDoc(_, _, ref docs)
-                | DocFragment::Include(_, _, _, ref docs) => acc.push_str(docs),
-            }
-
+            acc.push_str(&frag.doc);
             acc
         })
     }
@@ -536,54 +531,74 @@
         false
     }
 
-    pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
+    pub fn from_ast(
+        diagnostic: &::rustc_errors::Handler,
+        attrs: &[ast::Attribute],
+        additional_attrs: Option<(&[ast::Attribute], DefId)>,
+    ) -> Attributes {
         let mut doc_strings = vec![];
         let mut sp = None;
         let mut cfg = Cfg::True;
         let mut doc_line = 0;
 
-        let other_attrs = attrs
-            .iter()
-            .filter_map(|attr| {
-                if let Some(value) = attr.doc_str() {
-                    let value = beautify_doc_string(value);
-                    let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() {
-                        DocFragment::SugaredDoc
-                    } else {
-                        DocFragment::RawDoc
-                    };
-
-                    let line = doc_line;
-                    doc_line += value.lines().count();
-                    doc_strings.push(mk_fragment(line, attr.span, value));
-
-                    if sp.is_none() {
-                        sp = Some(attr.span);
-                    }
-                    None
+        let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
+            if let Some(value) = attr.doc_str() {
+                trace!("got doc_str={:?}", value);
+                let value = beautify_doc_string(value);
+                let kind = if attr.is_doc_comment() {
+                    DocFragmentKind::SugaredDoc
                 } else {
-                    if attr.has_name(sym::doc) {
-                        if let Some(mi) = attr.meta() {
-                            if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
-                                // Extracted #[doc(cfg(...))]
-                                match Cfg::parse(cfg_mi) {
-                                    Ok(new_cfg) => cfg &= new_cfg,
-                                    Err(e) => diagnostic.span_err(e.span, e.msg),
-                                }
-                            } else if let Some((filename, contents)) =
-                                Attributes::extract_include(&mi)
-                            {
-                                let line = doc_line;
-                                doc_line += contents.lines().count();
-                                doc_strings.push(DocFragment::Include(
-                                    line, attr.span, filename, contents,
-                                ));
+                    DocFragmentKind::RawDoc
+                };
+
+                let line = doc_line;
+                doc_line += value.lines().count();
+                doc_strings.push(DocFragment {
+                    line,
+                    span: attr.span,
+                    doc: value,
+                    kind,
+                    parent_module,
+                });
+
+                if sp.is_none() {
+                    sp = Some(attr.span);
+                }
+                None
+            } else {
+                if attr.has_name(sym::doc) {
+                    if let Some(mi) = attr.meta() {
+                        if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
+                            // Extracted #[doc(cfg(...))]
+                            match Cfg::parse(cfg_mi) {
+                                Ok(new_cfg) => cfg &= new_cfg,
+                                Err(e) => diagnostic.span_err(e.span, e.msg),
                             }
+                        } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
+                        {
+                            let line = doc_line;
+                            doc_line += contents.lines().count();
+                            doc_strings.push(DocFragment {
+                                line,
+                                span: attr.span,
+                                doc: contents,
+                                kind: DocFragmentKind::Include { filename },
+                                parent_module: parent_module,
+                            });
                         }
                     }
-                    Some(attr.clone())
                 }
-            })
+                Some(attr.clone())
+            }
+        };
+
+        // Additional documentation should be shown before the original documentation
+        let other_attrs = additional_attrs
+            .into_iter()
+            .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
+            .flatten()
+            .chain(attrs.iter().map(|attr| (attr, None)))
+            .filter_map(clean_attr)
             .collect();
 
         // treat #[target_feature(enable = "feat")] attributes as if they were
@@ -621,7 +636,7 @@
     /// Finds the `doc` attribute as a NameValue and returns the corresponding
     /// value found.
     pub fn doc_value(&self) -> Option<&str> {
-        self.doc_strings.first().map(|s| s.as_str())
+        self.doc_strings.first().map(|s| s.doc.as_str())
     }
 
     /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
@@ -665,9 +680,13 @@
                                     "../".repeat(depth)
                                 }
                                 Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(),
-                                Some(&(_, _, ExternalLocation::Unknown)) | None => {
-                                    String::from("https://doc.rust-lang.org/nightly")
-                                }
+                                Some(&(_, _, ExternalLocation::Unknown)) | None => String::from(
+                                    if UnstableFeatures::from_environment().is_nightly_build() {
+                                        "https://doc.rust-lang.org/nightly"
+                                    } else {
+                                        "https://doc.rust-lang.org"
+                                    },
+                                ),
                             };
                             // This is a primitive so the url is done "by hand".
                             let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
@@ -695,7 +714,7 @@
         self.other_attrs
             .lists(sym::doc)
             .filter(|a| a.has_name(sym::alias))
-            .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", "")))
+            .filter_map(|a| a.value_str().map(|s| s.to_string()))
             .filter(|v| !v.is_empty())
             .collect::<FxHashSet<_>>()
     }
@@ -1247,6 +1266,28 @@
 }
 
 impl PrimitiveType {
+    pub fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
+        match prim {
+            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
+            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
+            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
+            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
+            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
+            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
+            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
+            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
+            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
+            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
+            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
+            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
+            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
+            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
+            hir::PrimTy::Str => PrimitiveType::Str,
+            hir::PrimTy::Bool => PrimitiveType::Bool,
+            hir::PrimTy::Char => PrimitiveType::Char,
+        }
+    }
+
     pub fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
         match s {
             sym::isize => Some(PrimitiveType::Isize),
@@ -1622,11 +1663,28 @@
 }
 
 #[derive(Clone, Debug)]
-pub enum Import {
+pub struct Import {
+    pub kind: ImportKind,
+    pub source: ImportSource,
+    pub should_be_displayed: bool,
+}
+
+impl Import {
+    pub fn new_simple(name: String, source: ImportSource, should_be_displayed: bool) -> Self {
+        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
+    }
+
+    pub fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
+        Self { kind: ImportKind::Glob, source, should_be_displayed }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum ImportKind {
     // use source as str;
-    Simple(String, ImportSource),
+    Simple(String),
     // use source::*;
-    Glob(ImportSource),
+    Glob,
 }
 
 #[derive(Clone, Debug)]
@@ -1648,15 +1706,6 @@
 }
 
 #[derive(Clone, Debug)]
-pub struct Stability {
-    pub level: stability::StabilityLevel,
-    pub feature: String,
-    pub since: String,
-    pub unstable_reason: Option<String>,
-    pub issue: Option<NonZeroU32>,
-}
-
-#[derive(Clone, Debug)]
 pub struct Deprecation {
     pub since: Option<String>,
     pub note: Option<String>,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 58b76d2..b0ed233 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -3,12 +3,13 @@
 use crate::clean::{
     inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg,
     GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime,
-    MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type,
-    TypeBinding, TypeKind, Visibility, WherePredicate,
+    MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Type, TypeBinding,
+    TypeKind, Visibility, WherePredicate,
 };
 use crate::core::DocContext;
 
 use itertools::Itertools;
+use rustc_attr::Stability;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -102,14 +103,14 @@
 
 // extract the stability index for a node from tcx, if possible
 pub fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
-    cx.tcx.lookup_stability(def_id).clean(cx)
+    cx.tcx.lookup_stability(def_id).cloned()
 }
 
 pub fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
     cx.tcx.lookup_deprecation(def_id).clean(cx)
 }
 
-pub fn external_generic_args(
+fn external_generic_args(
     cx: &DocContext<'_>,
     trait_did: Option<DefId>,
     has_self: bool,
@@ -159,7 +160,7 @@
 
 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
 // from Fn<(A, B,), C> to Fn(A, B) -> C
-pub fn external_path(
+pub(super) fn external_path(
     cx: &DocContext<'_>,
     name: Symbol,
     trait_did: Option<DefId>,
@@ -361,7 +362,7 @@
         let primitive = match *target {
             ResolvedPath { did, .. } if did.is_local() => continue,
             ResolvedPath { did, .. } => {
-                ret.extend(inline::build_impls(cx, did, None));
+                ret.extend(inline::build_impls(cx, None, did, None));
                 continue;
             }
             _ => match target.primitive_type() {
@@ -371,7 +372,7 @@
         };
         for &did in primitive.impls(tcx) {
             if !did.is_local() {
-                inline::build_impl(cx, did, None, ret);
+                inline::build_impl(cx, None, did, None, ret);
             }
         }
     }
@@ -502,7 +503,7 @@
             format!("{}{}", format_integer_with_underscore_sep(&data.to_string()), ui.name_str())
         }
         (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Int(i)) => {
-            let ty = cx.tcx.lift(&ct.ty).unwrap();
+            let ty = cx.tcx.lift(ct.ty).unwrap();
             let size = cx.tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
             let sign_extended_data = sign_extend(data, size) as i128;
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 074a43f..45a84c4 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -328,6 +328,7 @@
     let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
     let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name;
     let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
+    let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name;
     let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name;
     let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name;
 
@@ -340,6 +341,7 @@
         private_doc_tests.to_owned(),
         no_crate_level_docs.to_owned(),
         invalid_codeblock_attributes_name.to_owned(),
+        invalid_html_tags.to_owned(),
         renamed_and_removed_lints.to_owned(),
         unknown_lints.to_owned(),
     ];
@@ -419,6 +421,7 @@
                 (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id)
             };
         }),
+        make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
     };
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 7b7c152..eb33890 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -95,6 +95,7 @@
         lint_caps,
         register_lints: None,
         override_queries: None,
+        make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
     };
 
@@ -926,7 +927,7 @@
         sp: Span,
         nested: F,
     ) {
-        let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs);
+        let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs, None);
         if let Some(ref cfg) = attrs.cfg {
             if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
                 return;
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index cfa51dc..ee217d9 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -8,6 +8,7 @@
 
 use rustc_hir as hir;
 use rustc_hir::def_id::CrateNum;
+use rustc_hir::HirId;
 
 pub struct Module<'hir> {
     pub name: Option<Symbol>,
@@ -236,6 +237,7 @@
 
 pub struct ExternCrate<'hir> {
     pub name: Symbol,
+    pub hir_id: HirId,
     pub cnum: CrateNum,
     pub path: Option<String>,
     pub vis: &'hir hir::Visibility<'hir>,
@@ -243,6 +245,7 @@
     pub span: Span,
 }
 
+#[derive(Debug)]
 pub struct Import<'hir> {
     pub name: Symbol,
     pub id: hir::HirId,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 2da9c68..d18282d 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1149,19 +1149,19 @@
 
 impl clean::Import {
     crate fn print(&self) -> impl fmt::Display + '_ {
-        display_fn(move |f| match *self {
-            clean::Import::Simple(ref name, ref src) => {
-                if *name == src.path.last_name() {
-                    write!(f, "use {};", src.print())
+        display_fn(move |f| match self.kind {
+            clean::ImportKind::Simple(ref name) => {
+                if *name == self.source.path.last_name() {
+                    write!(f, "use {};", self.source.print())
                 } else {
-                    write!(f, "use {} as {};", src.print(), *name)
+                    write!(f, "use {} as {};", self.source.print(), *name)
                 }
             }
-            clean::Import::Glob(ref src) => {
-                if src.path.segments.is_empty() {
+            clean::ImportKind::Glob => {
+                if self.source.path.segments.is_empty() {
                     write!(f, "use *;")
                 } else {
-                    write!(f, "use {}::*;", src.print())
+                    write!(f, "use {}::*;", self.source.print())
                 }
             }
         })
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 6c0f1c0..2fd06d7 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -43,7 +43,7 @@
 #[cfg(test)]
 mod tests;
 
-fn opts() -> Options {
+pub(crate) fn opts() -> Options {
     Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH
 }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 8b5ba7a..1726093 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -49,6 +49,7 @@
 
 use itertools::Itertools;
 use rustc_ast_pretty::pprust;
+use rustc_attr::StabilityLevel;
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_feature::UnstableFeatures;
@@ -539,11 +540,11 @@
         };
         let sidebar = if let Some(ref version) = cache.crate_version {
             format!(
-                "<p class='location'>Crate {}</p>\
-                     <div class='block version'>\
+                "<p class=\"location\">Crate {}</p>\
+                     <div class=\"block version\">\
                          <p>Version {}</p>\
                      </div>\
-                     <a id='all-types' href='index.html'><p>Back to index</p></a>",
+                     <a id=\"all-types\" href=\"index.html\"><p>Back to index</p></a>",
                 crate_name,
                 Escape(version),
             )
@@ -566,7 +567,7 @@
         page.root_path = "./";
 
         let mut style_files = self.shared.style_files.clone();
-        let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>";
+        let sidebar = "<p class=\"location\">Settings</p><div class=\"sidebar-elems\"></div>";
         style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false });
         let v = layout::render(
             &self.shared.layout,
@@ -575,7 +576,8 @@
             settings(
                 self.shared.static_root_path.as_deref().unwrap_or("./"),
                 &self.shared.resource_suffix,
-            ),
+                &self.shared.style_files,
+            )?,
             &style_files,
         );
         self.shared.fs.write(&settings_file, v.as_bytes())?;
@@ -806,10 +808,11 @@
 themePicker.onclick = switchThemeButtonState;
 themePicker.onblur = handleThemeButtonsBlur;
 {}.forEach(function(item) {{
-    var but = document.createElement('button');
+    var but = document.createElement("button");
     but.textContent = item;
     but.onclick = function(el) {{
         switchTheme(currentTheme, mainTheme, item, true);
+        useSystemTheme(false);
     }};
     but.onblur = handleThemeButtonsBlur;
     themes.appendChild(but);
@@ -1061,10 +1064,9 @@
             krates.dedup();
 
             let content = format!(
-                "<h1 class='fqn'>\
-                     <span class='in-band'>List of all crates</span>\
-                </h1>\
-                <ul class='crate mod'>{}</ul>",
+                "<h1 class=\"fqn\">\
+                     <span class=\"in-band\">List of all crates</span>\
+                </h1><ul class=\"crate mod\">{}</ul>",
                 krates
                     .iter()
                     .map(|s| {
@@ -1208,7 +1210,7 @@
 impl ItemEntry {
     crate fn print(&self) -> impl fmt::Display + '_ {
         crate::html::format::display_fn(move |f| {
-            write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name))
+            write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))
         })
     }
 }
@@ -1299,7 +1301,7 @@
         e.sort();
         write!(
             f,
-            "<h3 id='{}'>{}</h3><ul class='{} docblock'>{}</ul>",
+            "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">{}</ul>",
             title,
             Escape(title),
             class,
@@ -1312,16 +1314,16 @@
     fn print(self, f: &mut Buffer) {
         write!(
             f,
-            "<h1 class='fqn'>\
-                 <span class='out-of-band'>\
-                     <span id='render-detail'>\
+            "<h1 class=\"fqn\">\
+                 <span class=\"out-of-band\">\
+                     <span id=\"render-detail\">\
                          <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
                             title=\"collapse all docs\">\
-                             [<span class='inner'>&#x2212;</span>]\
+                             [<span class=\"inner\">&#x2212;</span>]\
                          </a>\
                      </span>
                  </span>
-                 <span class='in-band'>List of all items</span>\
+                 <span class=\"in-band\">List of all items</span>\
              </h1>"
         );
         print_entries(f, &self.structs, "Structs", "structs");
@@ -1343,40 +1345,75 @@
 
 #[derive(Debug)]
 enum Setting {
-    Section { description: &'static str, sub_settings: Vec<Setting> },
-    Entry { js_data_name: &'static str, description: &'static str, default_value: bool },
+    Section {
+        description: &'static str,
+        sub_settings: Vec<Setting>,
+    },
+    Toggle {
+        js_data_name: &'static str,
+        description: &'static str,
+        default_value: bool,
+    },
+    Select {
+        js_data_name: &'static str,
+        description: &'static str,
+        default_value: &'static str,
+        options: Vec<(String, String)>,
+    },
 }
 
 impl Setting {
-    fn display(&self) -> String {
+    fn display(&self, root_path: &str, suffix: &str) -> String {
         match *self {
-            Setting::Section { ref description, ref sub_settings } => format!(
-                "<div class='setting-line'>\
-                     <div class='title'>{}</div>\
-                     <div class='sub-settings'>{}</div>
+            Setting::Section { description, ref sub_settings } => format!(
+                "<div class=\"setting-line\">\
+                     <div class=\"title\">{}</div>\
+                     <div class=\"sub-settings\">{}</div>
                  </div>",
                 description,
-                sub_settings.iter().map(|s| s.display()).collect::<String>()
+                sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
             ),
-            Setting::Entry { ref js_data_name, ref description, ref default_value } => format!(
-                "<div class='setting-line'>\
-                     <label class='toggle'>\
-                     <input type='checkbox' id='{}' {}>\
-                     <span class='slider'></span>\
+            Setting::Toggle { js_data_name, description, default_value } => format!(
+                "<div class=\"setting-line\">\
+                     <label class=\"toggle\">\
+                     <input type=\"checkbox\" id=\"{}\" {}>\
+                     <span class=\"slider\"></span>\
                      </label>\
                      <div>{}</div>\
                  </div>",
                 js_data_name,
-                if *default_value { " checked" } else { "" },
+                if default_value { " checked" } else { "" },
                 description,
             ),
+            Setting::Select { js_data_name, description, default_value, ref options } => format!(
+                "<div class=\"setting-line\">\
+                     <div>{}</div>\
+                     <label class=\"select-wrapper\">\
+                         <select id=\"{}\" autocomplete=\"off\">{}</select>\
+                         <img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\
+                     </label>\
+                 </div>",
+                description,
+                js_data_name,
+                options
+                    .iter()
+                    .map(|opt| format!(
+                        "<option value=\"{}\" {}>{}</option>",
+                        opt.0,
+                        if &opt.0 == default_value { "selected" } else { "" },
+                        opt.1,
+                    ))
+                    .collect::<String>(),
+                root_path,
+                suffix,
+            ),
         }
     }
 }
 
 impl From<(&'static str, &'static str, bool)> for Setting {
     fn from(values: (&'static str, &'static str, bool)) -> Setting {
-        Setting::Entry { js_data_name: values.0, description: values.1, default_value: values.2 }
+        Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
     }
 }
 
@@ -1389,10 +1426,40 @@
     }
 }
 
-fn settings(root_path: &str, suffix: &str) -> String {
+fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
+    let theme_names: Vec<(String, String)> = themes
+        .iter()
+        .map(|entry| {
+            let theme =
+                try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
+                    .to_string();
+
+            Ok((theme.clone(), theme))
+        })
+        .collect::<Result<_, Error>>()?;
+
     // (id, explanation, default value)
     let settings: &[Setting] = &[
         (
+            "Theme preferences",
+            vec![
+                Setting::from(("use-system-theme", "Use system theme", true)),
+                Setting::Select {
+                    js_data_name: "preferred-dark-theme",
+                    description: "Preferred dark theme",
+                    default_value: "dark",
+                    options: theme_names.clone(),
+                },
+                Setting::Select {
+                    js_data_name: "preferred-light-theme",
+                    description: "Preferred light theme",
+                    default_value: "light",
+                    options: theme_names,
+                },
+            ],
+        )
+            .into(),
+        (
             "Auto-hide item declarations",
             vec![
                 ("auto-hide-struct", "Auto-hide structs declaration", true),
@@ -1413,16 +1480,17 @@
         ("line-numbers", "Show line numbers on code examples", false).into(),
         ("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
     ];
-    format!(
-        "<h1 class='fqn'>\
-    <span class='in-band'>Rustdoc settings</span>\
-</h1>\
-<div class='settings'>{}</div>\
-<script src='{}settings{}.js'></script>",
-        settings.iter().map(|s| s.display()).collect::<String>(),
+
+    Ok(format!(
+        "<h1 class=\"fqn\">\
+            <span class=\"in-band\">Rustdoc settings</span>\
+        </h1>\
+        <div class=\"settings\">{}</div>\
+        <script src=\"{}settings{}.js\"></script>",
+        settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
         root_path,
         suffix
-    )
+    ))
 }
 
 impl Context {
@@ -1611,20 +1679,20 @@
 fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) {
     debug_assert!(!item.is_stripped());
     // Write the breadcrumb trail header for the top
-    write!(buf, "<h1 class='fqn'><span class='out-of-band'>");
+    write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">");
     if let Some(version) = item.stable_since() {
         write!(
             buf,
-            "<span class='since' title='Stable since Rust version {0}'>{0}</span>",
+            "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
             version
         );
     }
     write!(
         buf,
-        "<span id='render-detail'>\
+        "<span id=\"render-detail\">\
                 <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
                     title=\"collapse all docs\">\
-                    [<span class='inner'>&#x2212;</span>]\
+                    [<span class=\"inner\">&#x2212;</span>]\
                 </a>\
             </span>"
     );
@@ -1637,12 +1705,16 @@
     // used to find the link to auto-click.
     if cx.shared.include_sources && !item.is_primitive() {
         if let Some(l) = cx.src_href(item, cache) {
-            write!(buf, "<a class='srclink' href='{}' title='{}'>[src]</a>", l, "goto source code");
+            write!(
+                buf,
+                "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
+                l, "goto source code"
+            );
         }
     }
 
     write!(buf, "</span>"); // out-of-band
-    write!(buf, "<span class='in-band'>");
+    write!(buf, "<span class=\"in-band\">");
     let name = match item.inner {
         clean::ModuleItem(ref m) => {
             if m.is_crate {
@@ -1682,13 +1754,13 @@
         for (i, component) in cur.iter().enumerate().take(amt) {
             write!(
                 buf,
-                "<a href='{}index.html'>{}</a>::<wbr>",
+                "<a href=\"{}index.html\">{}</a>::<wbr>",
                 "../".repeat(cur.len() - i - 1),
                 component
             );
         }
     }
-    write!(buf, "<a class=\"{}\" href=''>{}</a>", item.type_(), item.name.as_ref().unwrap());
+    write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap());
 
     write!(buf, "</span></h1>"); // in-band
 
@@ -1709,7 +1781,7 @@
         clean::ConstantItem(ref c) => item_constant(buf, cx, item, c),
         clean::ForeignTypeItem => item_foreign_type(buf, cx, item, cache),
         clean::KeywordItem(_) => item_keyword(buf, cx, item),
-        clean::OpaqueTyItem(ref e, _) => item_opaque_ty(buf, cx, item, e, cache),
+        clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e, cache),
         clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta, cache),
         _ => {
             // We don't generate pages for any other type.
@@ -1762,11 +1834,11 @@
     }
 }
 
-fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) {
+fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) {
     if let Some(ref name) = item.name {
         info!("Documenting {}", name);
     }
-    document_stability(w, cx, item, false);
+    document_stability(w, cx, item, false, parent);
     document_full(w, item, cx, "", false);
 }
 
@@ -1782,7 +1854,7 @@
     let mut ids = cx.id_map.borrow_mut();
     write!(
         w,
-        "<div class='docblock{}'>{}{}</div>",
+        "<div class=\"docblock{}\">{}{}</div>",
         if is_hidden { " hidden" } else { "" },
         prefix,
         Markdown(
@@ -1829,7 +1901,7 @@
     } else if !prefix.is_empty() {
         write!(
             w,
-            "<div class='docblock{}'>{}</div>",
+            "<div class=\"docblock{}\">{}</div>",
             if is_hidden { " hidden" } else { "" },
             prefix
         );
@@ -1843,17 +1915,23 @@
     } else if !prefix.is_empty() {
         write!(
             w,
-            "<div class='docblock{}'>{}</div>",
+            "<div class=\"docblock{}\">{}</div>",
             if is_hidden { " hidden" } else { "" },
             prefix
         );
     }
 }
 
-fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) {
-    let stabilities = short_stability(item, cx);
+fn document_stability(
+    w: &mut Buffer,
+    cx: &Context,
+    item: &clean::Item,
+    is_hidden: bool,
+    parent: Option<&clean::Item>,
+) {
+    let stabilities = short_stability(item, cx, parent);
     if !stabilities.is_empty() {
-        write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" });
+        write!(w, "<div class=\"stability{}\">", if is_hidden { " hidden" } else { "" });
         for stability in stabilities {
             write!(w, "{}", stability);
         }
@@ -1867,7 +1945,7 @@
 
 fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
     if item.is_non_exhaustive() {
-        write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
+        write!(w, "<div class=\"docblock non-exhaustive non-exhaustive-{}\">", {
             if item.is_struct() {
                 "struct"
             } else if item.is_enum() {
@@ -1951,7 +2029,7 @@
 }
 
 fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) {
-    document(w, cx, item);
+    document(w, cx, item, None);
 
     let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>();
 
@@ -1983,10 +2061,12 @@
         }
         let s1 = i1.stability.as_ref().map(|s| s.level);
         let s2 = i2.stability.as_ref().map(|s| s.level);
-        match (s1, s2) {
-            (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater,
-            (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less,
-            _ => {}
+        if let (Some(a), Some(b)) = (s1, s2) {
+            match (a.is_stable(), b.is_stable()) {
+                (true, true) | (false, false) => {}
+                (false, true) => return Ordering::Less,
+                (true, false) => return Ordering::Greater,
+            }
         }
         let lhs = i1.name.as_ref().map_or("", |s| &**s);
         let rhs = i2.name.as_ref().map_or("", |s| &**s);
@@ -2044,7 +2124,7 @@
             let (short, name) = item_ty_to_strs(&myty.unwrap());
             write!(
                 w,
-                "<h2 id='{id}' class='section-header'>\
+                "<h2 id=\"{id}\" class=\"section-header\">\
                        <a href=\"#{id}\">{name}</a></h2>\n<table>",
                 id = cx.derive_id(short.to_owned()),
                 name = name
@@ -2091,7 +2171,7 @@
                     clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
                         if func.header.unsafety == hir::Unsafety::Unsafe =>
                     {
-                        "<a title='unsafe function' href='#'><sup>⚠</sup></a>"
+                        "<a title=\"unsafe function\" href=\"#\"><sup>⚠</sup></a>"
                     }
                     _ => "",
                 };
@@ -2102,13 +2182,13 @@
                 let doc_value = myitem.doc_value().unwrap_or("");
                 write!(
                     w,
-                    "<tr class='{stab}{add}module-item'>\
+                    "<tr class=\"{stab}{add}module-item\">\
                          <td><a class=\"{class}\" href=\"{href}\" \
-                             title='{title}'>{name}</a>{unsafety_flag}</td>\
-                         <td class='docblock-short'>{stab_tags}{docs}</td>\
+                             title=\"{title}\">{name}</a>{unsafety_flag}</td>\
+                         <td class=\"docblock-short\">{stab_tags}{docs}</td>\
                      </tr>",
                     name = *myitem.name.as_ref().unwrap(),
-                    stab_tags = stability_tags(myitem),
+                    stab_tags = stability_tags(myitem, item),
                     docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(),
                     class = myitem.type_(),
                     add = add,
@@ -2132,7 +2212,7 @@
 
 /// Render the stability and deprecation tags that are displayed in the item's summary at the
 /// module level.
-fn stability_tags(item: &clean::Item) -> String {
+fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String {
     let mut tags = String::new();
 
     fn tag_html(class: &str, title: &str, contents: &str) -> String {
@@ -2150,16 +2230,19 @@
 
     // The "rustc_private" crates are permanently unstable so it makes no sense
     // to render "unstable" everywhere.
-    if item
-        .stability
-        .as_ref()
-        .map(|s| s.level == stability::Unstable && s.feature != "rustc_private")
+    if item.stability.as_ref().map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
         == Some(true)
     {
         tags += &tag_html("unstable", "", "Experimental");
     }
 
-    if let Some(ref cfg) = item.attrs.cfg {
+    let cfg = match (&item.attrs.cfg, parent.attrs.cfg.as_ref()) {
+        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
+        (cfg, _) => cfg.as_deref().cloned(),
+    };
+
+    debug!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg);
+    if let Some(ref cfg) = cfg {
         tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
     }
 
@@ -2168,7 +2251,7 @@
 
 /// Render the stability and/or deprecation warning that is displayed at the top of the item's
 /// documentation.
-fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
+fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec<String> {
     let mut stability = vec![];
     let error_codes = cx.shared.codes;
 
@@ -2197,23 +2280,24 @@
             message.push_str(&format!(": {}", html.into_string()));
         }
         stability.push(format!(
-            "<div class='stab deprecated'><span class='emoji'>👎</span> {}</div>",
+            "<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>",
             message,
         ));
     }
 
     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
-    if let Some(stab) = item
+    if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
         .stability
         .as_ref()
-        .filter(|stab| stab.level == stability::Unstable && stab.feature != "rustc_private")
+        .filter(|stab| stab.feature != sym::rustc_private)
+        .map(|stab| (stab.level, stab.feature))
     {
         let mut message =
-            "<span class='emoji'>🔬</span> This is a nightly-only experimental API.".to_owned();
+            "<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned();
 
-        let mut feature = format!("<code>{}</code>", Escape(&stab.feature));
-        if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
+        let mut feature = format!("<code>{}</code>", Escape(&feature.as_str()));
+        if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
             feature.push_str(&format!(
                 "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
                 url = url,
@@ -2223,13 +2307,13 @@
 
         message.push_str(&format!(" ({})", feature));
 
-        if let Some(unstable_reason) = &stab.unstable_reason {
+        if let Some(unstable_reason) = reason {
             let mut ids = cx.id_map.borrow_mut();
             message = format!(
                 "<details><summary>{}</summary>{}</details>",
                 message,
                 MarkdownHtml(
-                    &unstable_reason,
+                    &unstable_reason.as_str(),
                     &mut ids,
                     error_codes,
                     cx.shared.edition,
@@ -2239,18 +2323,29 @@
             );
         }
 
-        stability.push(format!("<div class='stab unstable'>{}</div>", message));
+        stability.push(format!("<div class=\"stab unstable\">{}</div>", message));
     }
 
-    if let Some(ref cfg) = item.attrs.cfg {
-        stability.push(format!("<div class='stab portability'>{}</div>", cfg.render_long_html()));
+    let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) {
+        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
+        (cfg, _) => cfg.as_deref().cloned(),
+    };
+
+    debug!(
+        "Portability {:?} - {:?} = {:?}",
+        item.attrs.cfg,
+        parent.and_then(|p| p.attrs.cfg.as_ref()),
+        cfg
+    );
+    if let Some(cfg) = cfg {
+        stability.push(format!("<div class=\"stab portability\">{}</div>", cfg.render_long_html()));
     }
 
     stability
 }
 
 fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Constant) {
-    write!(w, "<pre class='rust const'>");
+    write!(w, "<pre class=\"rust const\">");
     render_attributes(w, it, false);
 
     write!(
@@ -2281,21 +2376,21 @@
     }
 
     write!(w, "</pre>");
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) {
-    write!(w, "<pre class='rust static'>");
+    write!(w, "<pre class=\"rust static\">");
     render_attributes(w, it, false);
     write!(
         w,
-        "{vis}static {mutability} {name}: {typ}</pre>",
+        "{vis}static {mutability}{name}: {typ}</pre>",
         vis = it.visibility.print_with_space(),
         mutability = s.mutability.print_with_space(),
         name = it.name.as_ref().unwrap(),
         typ = s.type_.print()
     );
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) {
@@ -2310,7 +2405,7 @@
         f.generics.print()
     )
     .len();
-    write!(w, "<pre class='rust fn'>");
+    write!(w, "<pre class=\"rust fn\">");
     render_attributes(w, it, false);
     write!(
         w,
@@ -2328,7 +2423,7 @@
             .print(),
         spotlight = spotlight_decl(&f.decl),
     );
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn render_implementor(
@@ -2353,9 +2448,10 @@
         w,
         cx,
         implementor,
+        None,
         AssocItemLink::Anchor(None),
         RenderMode::Normal,
-        implementor.impl_item.stable_since(),
+        implementor.impl_item.stable_since().as_deref(),
         false,
         Some(use_absolute),
         false,
@@ -2382,9 +2478,10 @@
                 &mut buffer,
                 cx,
                 i,
+                Some(containing_item),
                 assoc_link,
                 RenderMode::Normal,
-                containing_item.stable_since(),
+                containing_item.stable_since().as_deref(),
                 true,
                 None,
                 false,
@@ -2432,7 +2529,7 @@
 
     // Output the trait definition
     wrap_into_docblock(w, |w| {
-        write!(w, "<pre class='rust trait'>");
+        write!(w, "<pre class=\"rust trait\">");
         render_attributes(w, it, true);
         write!(
             w,
@@ -2475,7 +2572,7 @@
                 write!(w, ";\n");
 
                 if pos < required.len() - 1 {
-                    write!(w, "<div class='item-spacer'></div>");
+                    write!(w, "<div class=\"item-spacer\"></div>");
                 }
             }
             if !required.is_empty() && !provided.is_empty() {
@@ -2492,7 +2589,7 @@
                     }
                 }
                 if pos < provided.len() - 1 {
-                    write!(w, "<div class='item-spacer'></div>");
+                    write!(w, "<div class=\"item-spacer\"></div>");
                 }
             }
             write!(w, "}}");
@@ -2501,32 +2598,33 @@
     });
 
     // Trait documentation
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) {
         write!(
             w,
-            "<h2 id='{0}' class='small-section-header'>\
-                {1}<a href='#{0}' class='anchor'></a>\
+            "<h2 id=\"{0}\" class=\"small-section-header\">\
+                {1}<a href=\"#{0}\" class=\"anchor\"></a>\
              </h2>{2}",
             id, title, extra_content
         )
     }
 
     fn write_loading_content(w: &mut Buffer, extra_content: &str) {
-        write!(w, "{}<span class='loading-content'>Loading content...</span>", extra_content)
+        write!(w, "{}<span class=\"loading-content\">Loading content...</span>", extra_content)
     }
 
     fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) {
         let name = m.name.as_ref().unwrap();
+        info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default());
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
-        write!(w, "<h3 id='{id}' class='method'><code>", id = id,);
+        write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,);
         render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
         write!(w, "</code>");
         render_stability_since(w, m, t);
         write!(w, "</h3>");
-        document(w, cx, m);
+        document(w, cx, m, Some(t));
     }
 
     if !types.is_empty() {
@@ -2534,7 +2632,7 @@
             w,
             "associated-types",
             "Associated Types",
-            "<div class='methods'>",
+            "<div class=\"methods\">",
         );
         for t in &types {
             trait_item(w, cx, *t, it);
@@ -2547,7 +2645,7 @@
             w,
             "associated-const",
             "Associated Constants",
-            "<div class='methods'>",
+            "<div class=\"methods\">",
         );
         for t in &consts {
             trait_item(w, cx, *t, it);
@@ -2561,7 +2659,7 @@
             w,
             "required-methods",
             "Required methods",
-            "<div class='methods'>",
+            "<div class=\"methods\">",
         );
         for m in &required {
             trait_item(w, cx, *m, it);
@@ -2573,7 +2671,7 @@
             w,
             "provided-methods",
             "Provided methods",
-            "<div class='methods'>",
+            "<div class=\"methods\">",
         );
         for m in &provided {
             trait_item(w, cx, *m, it);
@@ -2627,9 +2725,10 @@
                     w,
                     cx,
                     &implementor,
+                    None,
                     assoc_link,
                     RenderMode::Normal,
-                    implementor.impl_item.stable_since(),
+                    implementor.impl_item.stable_since().as_deref(),
                     false,
                     None,
                     true,
@@ -2645,7 +2744,7 @@
             w,
             "implementors",
             "Implementors",
-            "<div class='item-list' id='implementors-list'>",
+            "<div class=\"item-list\" id=\"implementors-list\">",
         );
         for implementor in concrete {
             render_implementor(cx, implementor, w, &implementor_dups, &[], cache);
@@ -2657,7 +2756,7 @@
                 w,
                 "synthetic-implementors",
                 "Auto implementors",
-                "<div class='item-list' id='synthetic-implementors-list'>",
+                "<div class=\"item-list\" id=\"synthetic-implementors-list\">",
             );
             for implementor in synthetic {
                 render_implementor(
@@ -2678,7 +2777,7 @@
             w,
             "implementors",
             "Implementors",
-            "<div class='item-list' id='implementors-list'>",
+            "<div class=\"item-list\" id=\"implementors-list\">",
         );
         write_loading_content(w, "</div>");
 
@@ -2687,7 +2786,7 @@
                 w,
                 "synthetic-implementors",
                 "Auto implementors",
-                "<div class='item-list' id='synthetic-implementors-list'>",
+                "<div class=\"item-list\" id=\"synthetic-implementors-list\">",
             );
             write_loading_content(w, "</div>");
         }
@@ -2739,7 +2838,7 @@
 ) {
     write!(
         w,
-        "{}{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
+        "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}",
         extra,
         it.visibility.print_with_space(),
         naive_assoc_href(it, link),
@@ -2758,7 +2857,7 @@
 ) {
     write!(
         w,
-        "{}type <a href='{}' class=\"type\">{}</a>",
+        "{}type <a href=\"{}\" class=\"type\">{}</a>",
         extra,
         naive_assoc_href(it, link),
         it.name.as_ref().unwrap()
@@ -2774,13 +2873,17 @@
 fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: Option<&str>) {
     if let Some(v) = ver {
         if containing_ver != ver && !v.is_empty() {
-            write!(w, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", v)
+            write!(w, "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", v)
         }
     }
 }
 
 fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) {
-    render_stability_since_raw(w, item.stable_since(), containing_item.stable_since())
+    render_stability_since_raw(
+        w,
+        item.stable_since().as_deref(),
+        containing_item.stable_since().as_deref(),
+    )
 }
 
 fn render_assoc_item(
@@ -2836,7 +2939,7 @@
         render_attributes(w, meth, false);
         write!(
             w,
-            "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
+            "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
              {generics}{decl}{spotlight}{where_clause}",
             if parent == ItemType::Trait { "    " } else { "" },
             meth.visibility.print_with_space(),
@@ -2879,13 +2982,13 @@
 
 fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct, cache: &Cache) {
     wrap_into_docblock(w, |w| {
-        write!(w, "<pre class='rust struct'>");
+        write!(w, "<pre class=\"rust struct\">");
         render_attributes(w, it, true);
         render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true);
         write!(w, "</pre>")
     });
 
-    document(w, cx, it);
+    document(w, cx, it, None);
     let mut fields = s
         .fields
         .iter()
@@ -2898,8 +3001,8 @@
         if fields.peek().is_some() {
             write!(
                 w,
-                "<h2 id='fields' class='fields small-section-header'>
-                       Fields{}<a href='#fields' class='anchor'></a></h2>",
+                "<h2 id=\"fields\" class=\"fields small-section-header\">
+                       Fields{}<a href=\"#fields\" class=\"anchor\"></a></h2>",
                 document_non_exhaustive_header(it)
             );
             document_non_exhaustive(w, it);
@@ -2920,7 +3023,7 @@
                     name = field.name.as_ref().unwrap(),
                     ty = ty.print()
                 );
-                document(w, cx, field);
+                document(w, cx, field, Some(it));
             }
         }
     }
@@ -2929,13 +3032,13 @@
 
 fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, cache: &Cache) {
     wrap_into_docblock(w, |w| {
-        write!(w, "<pre class='rust union'>");
+        write!(w, "<pre class=\"rust union\">");
         render_attributes(w, it, true);
         render_union(w, it, Some(&s.generics), &s.fields, "", true);
         write!(w, "</pre>")
     });
 
-    document(w, cx, it);
+    document(w, cx, it, None);
     let mut fields = s
         .fields
         .iter()
@@ -2947,8 +3050,8 @@
     if fields.peek().is_some() {
         write!(
             w,
-            "<h2 id='fields' class='fields small-section-header'>
-                   Fields<a href='#fields' class='anchor'></a></h2>"
+            "<h2 id=\"fields\" class=\"fields small-section-header\">
+                   Fields<a href=\"#fields\" class=\"anchor\"></a></h2>"
         );
         for (field, ty) in fields {
             let name = field.name.as_ref().expect("union field name");
@@ -2965,9 +3068,9 @@
                 ty = ty.print()
             );
             if let Some(stability_class) = field.stability_class() {
-                write!(w, "<span class='stab {stab}'></span>", stab = stability_class);
+                write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
             }
-            document(w, cx, field);
+            document(w, cx, field, Some(it));
         }
     }
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
@@ -2975,7 +3078,7 @@
 
 fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, cache: &Cache) {
     wrap_into_docblock(w, |w| {
-        write!(w, "<pre class='rust enum'>");
+        write!(w, "<pre class=\"rust enum\">");
         render_attributes(w, it, true);
         write!(
             w,
@@ -3022,12 +3125,12 @@
         write!(w, "</pre>")
     });
 
-    document(w, cx, it);
+    document(w, cx, it, None);
     if !e.variants.is_empty() {
         write!(
             w,
-            "<h2 id='variants' class='variants small-section-header'>
-                   Variants{}<a href='#variants' class='anchor'></a></h2>\n",
+            "<h2 id=\"variants\" class=\"variants small-section-header\">
+                   Variants{}<a href=\"#variants\" class=\"anchor\"></a></h2>\n",
             document_non_exhaustive_header(it)
         );
         document_non_exhaustive(w, it);
@@ -3055,7 +3158,7 @@
                 }
             }
             write!(w, "</code></div>");
-            document(w, cx, variant);
+            document(w, cx, variant, Some(it));
             document_non_exhaustive(w, variant);
 
             use crate::clean::{Variant, VariantKind};
@@ -3066,7 +3169,7 @@
                     ItemType::Variant,
                     variant.name.as_ref().unwrap()
                 ));
-                write!(w, "<div class='autohide sub-variant' id='{id}'>", id = variant_id);
+                write!(w, "<div class=\"autohide sub-variant\" id=\"{id}\">", id = variant_id);
                 write!(
                     w,
                     "<h3>Fields of <b>{name}</b></h3><div>",
@@ -3090,7 +3193,7 @@
                             f = field.name.as_ref().unwrap(),
                             t = ty.print()
                         );
-                        document(w, cx, field);
+                        document(w, cx, field, Some(variant));
                     }
                 }
                 write!(w, "</div></div>");
@@ -3288,6 +3391,10 @@
     what: AssocItemRender<'_>,
     cache: &Cache,
 ) {
+    info!(
+        "Documenting associated items of {}",
+        containing_item.name.as_deref().unwrap_or_default()
+    );
     let v = match cache.impls.get(&it) {
         Some(v) => v,
         None => return,
@@ -3298,8 +3405,8 @@
             AssocItemRender::All => {
                 write!(
                     w,
-                    "<h2 id='implementations' class='small-section-header'>\
-                         Implementations<a href='#implementations' class='anchor'></a>\
+                    "<h2 id=\"implementations\" class=\"small-section-header\">\
+                         Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
                     </h2>"
                 );
                 RenderMode::Normal
@@ -3307,9 +3414,9 @@
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                 write!(
                     w,
-                    "<h2 id='deref-methods' class='small-section-header'>\
+                    "<h2 id=\"deref-methods\" class=\"small-section-header\">\
                          Methods from {}&lt;Target = {}&gt;\
-                         <a href='#deref-methods' class='anchor'></a>\
+                         <a href=\"#deref-methods\" class=\"anchor\"></a>\
                      </h2>",
                     trait_.print(),
                     type_.print()
@@ -3322,9 +3429,10 @@
                 w,
                 cx,
                 i,
+                Some(containing_item),
                 AssocItemLink::Anchor(None),
                 render_mode,
-                containing_item.stable_since(),
+                containing_item.stable_since().as_deref(),
                 true,
                 None,
                 false,
@@ -3357,10 +3465,10 @@
         if !impls.is_empty() {
             write!(
                 w,
-                "<h2 id='trait-implementations' class='small-section-header'>\
-                     Trait Implementations<a href='#trait-implementations' class='anchor'></a>\
+                "<h2 id=\"trait-implementations\" class=\"small-section-header\">\
+                     Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\
                  </h2>\
-                 <div id='trait-implementations-list'>{}</div>",
+                 <div id=\"trait-implementations-list\">{}</div>",
                 impls
             );
         }
@@ -3368,11 +3476,11 @@
         if !synthetic.is_empty() {
             write!(
                 w,
-                "<h2 id='synthetic-implementations' class='small-section-header'>\
+                "<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\
                      Auto Trait Implementations\
-                     <a href='#synthetic-implementations' class='anchor'></a>\
+                     <a href=\"#synthetic-implementations\" class=\"anchor\"></a>\
                  </h2>\
-                 <div id='synthetic-implementations-list'>"
+                 <div id=\"synthetic-implementations-list\">"
             );
             render_impls(cx, w, &synthetic, containing_item, cache);
             write!(w, "</div>");
@@ -3381,11 +3489,11 @@
         if !blanket_impl.is_empty() {
             write!(
                 w,
-                "<h2 id='blanket-implementations' class='small-section-header'>\
+                "<h2 id=\"blanket-implementations\" class=\"small-section-header\">\
                      Blanket Implementations\
-                     <a href='#blanket-implementations' class='anchor'></a>\
+                     <a href=\"#blanket-implementations\" class=\"anchor\"></a>\
                  </h2>\
-                 <div id='blanket-implementations-list'>"
+                 <div id=\"blanket-implementations-list\">"
             );
             render_impls(cx, w, &blanket_impl, containing_item, cache);
             write!(w, "</div>");
@@ -3500,8 +3608,8 @@
     if !out.is_empty() {
         out.insert_str(
             0,
-            "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ<div class='notable-traits-tooltiptext'><span class=\"docblock\">"
-
+            "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
+            <div class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
         );
         out.push_str("</code></span></div></span></span>");
     }
@@ -3513,6 +3621,7 @@
     w: &mut Buffer,
     cx: &Context,
     i: &Impl,
+    parent: Option<&clean::Item>,
     link: AssocItemLink<'_>,
     render_mode: RenderMode,
     outer_version: Option<&str>,
@@ -3542,7 +3651,7 @@
             format!(" aliases=\"{}\"", aliases.join(","))
         };
         if let Some(use_absolute) = use_absolute {
-            write!(w, "<h3 id='{}' class='impl'{}><code class='in-band'>", id, aliases);
+            write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases);
             fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute);
             if show_def_docs {
                 for it in &i.inner_impl().items {
@@ -3557,24 +3666,31 @@
         } else {
             write!(
                 w,
-                "<h3 id='{}' class='impl'{}><code class='in-band'>{}</code>",
+                "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
                 id,
                 aliases,
                 i.inner_impl().print()
             );
         }
-        write!(w, "<a href='#{}' class='anchor'></a>", id);
-        let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
-        render_stability_since_raw(w, since, outer_version);
+        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+        let since = i.impl_item.stability.as_ref().and_then(|s| match s.level {
+            StabilityLevel::Stable { since } => Some(since.as_str()),
+            StabilityLevel::Unstable { .. } => None,
+        });
+        render_stability_since_raw(w, since.as_deref(), outer_version);
         if let Some(l) = cx.src_href(&i.impl_item, cache) {
-            write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>", l, "goto source code");
+            write!(
+                w,
+                "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
+                l, "goto source code"
+            );
         }
         write!(w, "</h3>");
         if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
             let mut ids = cx.id_map.borrow_mut();
             write!(
                 w,
-                "<div class='docblock'>{}</div>",
+                "<div class=\"docblock\">{}</div>",
                 Markdown(
                     &*dox,
                     &i.impl_item.links(),
@@ -3592,6 +3708,7 @@
         w: &mut Buffer,
         cx: &Context,
         item: &clean::Item,
+        parent: Option<&clean::Item>,
         link: AssocItemLink<'_>,
         render_mode: RenderMode,
         is_default_item: bool,
@@ -3622,15 +3739,15 @@
                 // Only render when the method is not static or we allow static methods
                 if render_method_item {
                     let id = cx.derive_id(format!("{}.{}", item_type, name));
-                    write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class);
+                    write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, extra_class);
                     write!(w, "<code>");
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
                     write!(w, "</code>");
-                    render_stability_since_raw(w, item.stable_since(), outer_version);
+                    render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
                     if let Some(l) = cx.src_href(item, cache) {
                         write!(
                             w,
-                            "<a class='srclink' href='{}' title='{}'>[src]</a>",
+                            "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
                             l, "goto source code"
                         );
                     }
@@ -3639,20 +3756,20 @@
             }
             clean::TypedefItem(ref tydef, _) => {
                 let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name));
-                write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class);
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
                 assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "");
                 write!(w, "</code></h4>");
             }
             clean::AssocConstItem(ref ty, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
-                write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class);
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "");
                 write!(w, "</code>");
-                render_stability_since_raw(w, item.stable_since(), outer_version);
+                render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
                 if let Some(l) = cx.src_href(item, cache) {
                     write!(
                         w,
-                        "<a class='srclink' href='{}' title='{}'>[src]</a>",
+                        "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>",
                         l, "goto source code"
                     );
                 }
@@ -3660,7 +3777,7 @@
             }
             clean::AssocTypeItem(ref bounds, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
-                write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class);
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
                 assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "");
                 write!(w, "</code></h4>");
             }
@@ -3676,7 +3793,7 @@
                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
                         // We need the stability of the item from the trait
                         // because impls can't have a stability.
-                        document_stability(w, cx, it, is_hidden);
+                        document_stability(w, cx, it, is_hidden, parent);
                         if item.doc_value().is_some() {
                             document_full(w, item, cx, "", is_hidden);
                         } else if show_def_docs {
@@ -3686,13 +3803,13 @@
                         }
                     }
                 } else {
-                    document_stability(w, cx, item, is_hidden);
+                    document_stability(w, cx, item, is_hidden, parent);
                     if show_def_docs {
                         document_full(w, item, cx, "", is_hidden);
                     }
                 }
             } else {
-                document_stability(w, cx, item, is_hidden);
+                document_stability(w, cx, item, is_hidden, parent);
                 if show_def_docs {
                     document_short(w, item, link, "", is_hidden);
                 }
@@ -3703,12 +3820,13 @@
     let traits = &cache.traits;
     let trait_ = i.trait_did().map(|did| &traits[&did]);
 
-    write!(w, "<div class='impl-items'>");
+    write!(w, "<div class=\"impl-items\">");
     for trait_item in &i.inner_impl().items {
         doc_impl_item(
             w,
             cx,
             trait_item,
+            parent,
             link,
             render_mode,
             false,
@@ -3724,6 +3842,7 @@
         cx: &Context,
         t: &clean::Trait,
         i: &clean::Impl,
+        parent: Option<&clean::Item>,
         render_mode: RenderMode,
         outer_version: Option<&str>,
         show_def_docs: bool,
@@ -3741,6 +3860,7 @@
                 w,
                 cx,
                 trait_item,
+                parent,
                 assoc_link,
                 render_mode,
                 true,
@@ -3763,6 +3883,7 @@
                 cx,
                 t,
                 &i.inner_impl(),
+                parent,
                 render_mode,
                 outer_version,
                 show_def_docs,
@@ -3780,7 +3901,7 @@
     t: &clean::OpaqueTy,
     cache: &Cache,
 ) {
-    write!(w, "<pre class='rust opaque'>");
+    write!(w, "<pre class=\"rust opaque\">");
     render_attributes(w, it, false);
     write!(
         w,
@@ -3791,7 +3912,7 @@
         bounds = bounds(&t.bounds, false)
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -3807,7 +3928,7 @@
     t: &clean::TraitAlias,
     cache: &Cache,
 ) {
-    write!(w, "<pre class='rust trait-alias'>");
+    write!(w, "<pre class=\"rust trait-alias\">");
     render_attributes(w, it, false);
     write!(
         w,
@@ -3818,7 +3939,7 @@
         bounds(&t.bounds, true)
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -3828,7 +3949,7 @@
 }
 
 fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typedef, cache: &Cache) {
-    write!(w, "<pre class='rust typedef'>");
+    write!(w, "<pre class=\"rust typedef\">");
     render_attributes(w, it, false);
     write!(
         w,
@@ -3839,7 +3960,7 @@
         type_ = t.type_.print()
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -3849,7 +3970,7 @@
 }
 
 fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) {
-    writeln!(w, "<pre class='rust foreigntype'>extern {{");
+    writeln!(w, "<pre class=\"rust foreigntype\">extern {{");
     render_attributes(w, it, false);
     write!(
         w,
@@ -3858,7 +3979,7 @@
         it.name.as_ref().unwrap(),
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
@@ -3876,7 +3997,7 @@
     {
         write!(
             buffer,
-            "<p class='location'>{}{}</p>",
+            "<p class=\"location\">{}{}</p>",
             match it.inner {
                 clean::StructItem(..) => "Struct ",
                 clean::TraitItem(..) => "Trait ",
@@ -3901,7 +4022,7 @@
         if let Some(ref version) = cache.crate_version {
             write!(
                 buffer,
-                "<div class='block version'>\
+                "<div class=\"block version\">\
                      <p>Version {}</p>\
                  </div>",
                 Escape(version)
@@ -3913,7 +4034,7 @@
     if it.is_crate() {
         write!(
             buffer,
-            "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
+            "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
             it.name.as_ref().expect("crates always have a name")
         );
     }
@@ -3937,14 +4058,14 @@
     // as much HTML as possible in order to allow non-JS-enabled browsers
     // to navigate the documentation (though slightly inefficiently).
 
-    write!(buffer, "<p class='location'>");
+    write!(buffer, "<p class=\"location\">");
     for (i, name) in cx.current.iter().take(parentlen).enumerate() {
         if i > 0 {
             write!(buffer, "::<wbr>");
         }
         write!(
             buffer,
-            "<a href='{}index.html'>{}</a>",
+            "<a href=\"{}index.html\">{}</a>",
             &cx.root_path()[..(cx.current.len() - i - 1) * 3],
             *name
         );
@@ -3956,9 +4077,9 @@
     write!(
         buffer,
         "<script>window.sidebarCurrent = {{\
-                name: '{name}', \
-                ty: '{ty}', \
-                relpath: '{path}'\
+                name: \"{name}\", \
+                ty: \"{ty}\", \
+                relpath: \"{path}\"\
             }};</script>",
         name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""),
         ty = it.type_(),
@@ -4438,8 +4559,9 @@
 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
     let mut sidebar = String::new();
 
-    if items.iter().any(|it| it.type_() == ItemType::ExternCrate || it.type_() == ItemType::Import)
-    {
+    if items.iter().any(|it| {
+        it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
+    }) {
         sidebar.push_str(&format!(
             "<li><a href=\"#{id}\">{name}</a></li>",
             id = "reexports",
@@ -4502,24 +4624,24 @@
             None,
         ))
     });
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) {
     let name = it.name.as_ref().expect("proc-macros always have names");
     match m.kind {
         MacroKind::Bang => {
-            write!(w, "<pre class='rust macro'>");
+            write!(w, "<pre class=\"rust macro\">");
             write!(w, "{}!() {{ /* proc-macro */ }}", name);
             write!(w, "</pre>");
         }
         MacroKind::Attr => {
-            write!(w, "<pre class='rust attr'>");
+            write!(w, "<pre class=\"rust attr\">");
             write!(w, "#[{}]", name);
             write!(w, "</pre>");
         }
         MacroKind::Derive => {
-            write!(w, "<pre class='rust derive'>");
+            write!(w, "<pre class=\"rust derive\">");
             write!(w, "#[derive({})]", name);
             if !m.helpers.is_empty() {
                 writeln!(w, "\n{{");
@@ -4532,16 +4654,16 @@
             write!(w, "</pre>");
         }
     }
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) {
-    document(w, cx, it);
+    document(w, cx, it, None);
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
 fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) {
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 02a7362..b487b39 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -84,7 +84,7 @@
         };
 
         // Remove the utf-8 BOM if any
-        if contents.starts_with("\u{feff}") {
+        if contents.starts_with('\u{feff}') {
             contents.drain(..3);
         }
 
@@ -99,16 +99,15 @@
             href.push('/');
         });
         self.scx.ensure_dir(&cur)?;
-        let mut fname = p.file_name().expect("source has no filename").to_os_string();
+
+        let src_fname = p.file_name().expect("source has no filename").to_os_string();
+        let mut fname = src_fname.clone();
         fname.push(".html");
         cur.push(&fname);
         href.push_str(&fname.to_string_lossy());
 
-        let title = format!(
-            "{} -- source",
-            cur.file_name().expect("failed to get file name").to_string_lossy()
-        );
-        let desc = format!("Source to the Rust file `{}`.", filename);
+        let title = format!("{} - source", src_fname.to_string_lossy());
+        let desc = format!("Source of the Rust file `{}`.", filename);
         let page = layout::Page {
             title: &title,
             css_class: "source",
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 1b3eb20..e382e5a 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2716,10 +2716,6 @@
         };
     }
 
-    window.onresize = function() {
-        hideSidebar();
-    };
-
     if (main) {
         onEachLazy(main.getElementsByClassName("loading-content"), function(e) {
             e.remove();
@@ -2796,6 +2792,10 @@
         addClass(popup, "hidden");
         popup.id = "help";
 
+        var book_info = document.createElement("span");
+        book_info.innerHTML = "You can find more information in \
+            <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
+
         var container = document.createElement("div");
         var shortcuts = [
             ["?", "Show this help dialog"],
@@ -2829,6 +2829,7 @@
         addClass(div_infos, "infos");
         div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
 
+        container.appendChild(book_info);
         container.appendChild(div_shortcuts);
         container.appendChild(div_infos);
 
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 935b96e..7eccb09 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -120,7 +120,7 @@
 }
 
 h1, h2, h3, h4,
-.sidebar, a.source, .search-input, .content table :not(code)>a,
+.sidebar, a.source, .search-input, .content table td:first-child > a,
 .collapse-toggle, div.item-list .out-of-band,
 #source-sidebar, #sidebar-toggle {
 	font-family: "Fira Sans", sans-serif;
@@ -390,17 +390,13 @@
 	cursor: pointer;
 }
 
+.docblock-short {
+	overflow-wrap: anywhere;
+}
 .docblock-short p {
 	display: inline;
 }
 
-.docblock-short.nowrap {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-
 .docblock-short p {
 	overflow: hidden;
 	text-overflow: ellipsis;
@@ -800,14 +796,22 @@
 	clear: left;
 	display: block;
 }
+#help > div > span {
+	text-align: center;
+	display: block;
+	margin: 10px 0;
+	font-size: 18px;
+	border-bottom: 1px solid #ccc;
+	padding-bottom: 4px;
+	margin-bottom: 6px;
+}
 #help dd { margin: 5px 35px; }
 #help .infos { padding-left: 0; }
 #help h1, #help h2 { margin-top: 0; }
 #help > div div {
 	width: 50%;
 	float: left;
-	padding: 20px;
-	padding-left: 17px;
+	padding: 0 20px 20px 17px;;
 }
 
 .stab {
@@ -1098,6 +1102,10 @@
 	border-style: solid;
 }
 
+.tooltip:hover .tooltiptext {
+	display: inline;
+}
+
 .tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
 	font-weight: bold;
 	font-size: 20px;
@@ -1540,6 +1548,14 @@
 		left: 0;
 		top: 100%;
 	}
+
+	/* We don't display the help button on mobile devices. */
+	.help-button {
+		display: none;
+	}
+	.search-container > div {
+		width: calc(100% - 32px);
+	}
 }
 
 @media print {
@@ -1549,12 +1565,43 @@
 }
 
 @media (max-width: 416px) {
-	#titles {
+	#titles, #titles > div {
 		height: 73px;
 	}
 
-	#titles > div {
-		height: 73px;
+	#main > table:not(.table-display) td {
+		word-break: break-word;
+		min-width: 10%;
+	}
+
+	.search-container > div {
+		display: block;
+		width: calc(100% - 37px);
+	}
+
+	#crate-search {
+		width: 100%;
+		border-radius: 4px;
+		border: 0;
+	}
+
+	#crate-search + .search-input {
+		width: calc(100% + 71px);
+		margin-left: -36px;
+	}
+
+	#theme-picker, #settings-menu {
+		padding: 5px;
+		width: 31px;
+		height: 31px;
+	}
+
+	#theme-picker {
+		margin-top: -2px;
+	}
+
+	#settings-menu {
+		top: 7px;
 	}
 }
 
diff --git a/src/librustdoc/html/static/settings.css b/src/librustdoc/html/static/settings.css
index d03cf7f..4bacd7b 100644
--- a/src/librustdoc/html/static/settings.css
+++ b/src/librustdoc/html/static/settings.css
@@ -4,7 +4,6 @@
 }
 
 .setting-line > div {
-	max-width: calc(100% - 74px);
 	display: inline-block;
 	vertical-align: top;
 	font-size: 17px;
@@ -30,6 +29,38 @@
 	display: none;
 }
 
+.select-wrapper {
+	float: right;
+	position: relative;
+	height: 27px;
+	min-width: 25%;
+}
+
+.select-wrapper select {
+	appearance: none;
+	-moz-appearance: none;
+	-webkit-appearance: none;
+	background: none;
+	border: 2px solid #ccc;
+	padding-right: 28px;
+	width: 100%;
+}
+
+.select-wrapper img {
+	pointer-events: none;
+	position: absolute;
+	right: 0;
+	bottom: 0;
+	background: #ccc;
+	height: 100%;
+	width: 28px;
+	padding: 0px 4px;
+}
+
+.select-wrapper select option {
+	color: initial;
+}
+
 .slider {
 	position: absolute;
 	cursor: pointer;
diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js
index 427a74c..00a01ac 100644
--- a/src/librustdoc/html/static/settings.js
+++ b/src/librustdoc/html/static/settings.js
@@ -1,30 +1,56 @@
 // Local js definitions:
-/* global getCurrentValue, updateLocalStorage */
+/* global getCurrentValue, updateLocalStorage, updateSystemTheme */
 
 (function () {
-    function changeSetting(settingName, isEnabled) {
-        updateLocalStorage('rustdoc-' + settingName, isEnabled);
+    function changeSetting(settingName, value) {
+        updateLocalStorage("rustdoc-" + settingName, value);
+
+        switch (settingName) {
+            case "preferred-dark-theme":
+            case "preferred-light-theme":
+            case "use-system-theme":
+                updateSystemTheme();
+                break;
+        }
     }
 
     function getSettingValue(settingName) {
-        return getCurrentValue('rustdoc-' + settingName);
+        return getCurrentValue("rustdoc-" + settingName);
     }
 
     function setEvents() {
-        var elems = document.getElementsByClassName("slider");
-        if (!elems || elems.length === 0) {
-            return;
-        }
-        for (var i = 0; i < elems.length; ++i) {
-            var toggle = elems[i].previousElementSibling;
-            var settingId = toggle.id;
-            var settingValue = getSettingValue(settingId);
-            if (settingValue !== null) {
-                toggle.checked = settingValue === "true";
+        var elems = {
+            toggles: document.getElementsByClassName("slider"),
+            selects: document.getElementsByClassName("select-wrapper")
+        };
+        var i;
+
+        if (elems.toggles && elems.toggles.length > 0) {
+            for (i = 0; i < elems.toggles.length; ++i) {
+                var toggle = elems.toggles[i].previousElementSibling;
+                var settingId = toggle.id;
+                var settingValue = getSettingValue(settingId);
+                if (settingValue !== null) {
+                    toggle.checked = settingValue === "true";
+                }
+                toggle.onchange = function() {
+                    changeSetting(this.id, this.checked);
+                };
             }
-            toggle.onchange = function() {
-                changeSetting(this.id, this.checked);
-            };
+        }
+
+        if (elems.selects && elems.selects.length > 0) {
+            for (i = 0; i < elems.selects.length; ++i) {
+                var select = elems.selects[i].getElementsByTagName("select")[0];
+                var settingId = select.id;
+                var settingValue = getSettingValue(settingId);
+                if (settingValue !== null) {
+                    select.value = settingValue;
+                }
+                select.onchange = function() {
+                    changeSetting(this.id, this.value);
+                };
+            }
         }
     }
 
diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js
index 0a2fae2..a027d68 100644
--- a/src/librustdoc/html/static/storage.js
+++ b/src/librustdoc/html/static/storage.js
@@ -1,8 +1,10 @@
 // From rust:
 /* global resourcesSuffix */
 
+var darkThemes = ["dark", "ayu"];
 var currentTheme = document.getElementById("themeStyle");
 var mainTheme = document.getElementById("mainThemeStyle");
+var localStoredTheme = getCurrentValue("rustdoc-theme");
 
 var savedHref = [];
 
@@ -110,19 +112,90 @@
     });
     if (found === true) {
         styleElem.href = newHref;
-        // If this new value comes from a system setting or from the previously saved theme, no
-        // need to save it.
+        // If this new value comes from a system setting or from the previously
+        // saved theme, no need to save it.
         if (saveTheme === true) {
             updateLocalStorage("rustdoc-theme", newTheme);
         }
     }
 }
 
-function getSystemValue() {
-    var property = getComputedStyle(document.documentElement).getPropertyValue('content');
-    return property.replace(/[\"\']/g, "");
+function useSystemTheme(value) {
+    if (value === undefined) {
+        value = true;
+    }
+
+    updateLocalStorage("rustdoc-use-system-theme", value);
+
+    // update the toggle if we're on the settings page
+    var toggle = document.getElementById("use-system-theme");
+    if (toggle && toggle instanceof HTMLInputElement) {
+        toggle.checked = value;
+    }
 }
 
-switchTheme(currentTheme, mainTheme,
-            getCurrentValue("rustdoc-theme") || getSystemValue() || "light",
-            false);
+var updateSystemTheme = (function() {
+    if (!window.matchMedia) {
+        // fallback to the CSS computed value
+        return function() {
+            let cssTheme = getComputedStyle(document.documentElement)
+                .getPropertyValue('content');
+
+            switchTheme(
+                currentTheme,
+                mainTheme,
+                JSON.parse(cssTheme) || light,
+                true
+            );
+        };
+    }
+
+    // only listen to (prefers-color-scheme: dark) because light is the default
+    var mql = window.matchMedia("(prefers-color-scheme: dark)");
+
+    function handlePreferenceChange(mql) {
+        // maybe the user has disabled the setting in the meantime!
+        if (getCurrentValue("rustdoc-use-system-theme") !== "false") {
+            var lightTheme = getCurrentValue("rustdoc-preferred-light-theme") || "light";
+            var darkTheme = getCurrentValue("rustdoc-preferred-dark-theme") || "dark";
+
+            if (mql.matches) {
+                // prefers a dark theme
+                switchTheme(currentTheme, mainTheme, darkTheme, true);
+            } else {
+                // prefers a light theme, or has no preference
+                switchTheme(currentTheme, mainTheme, lightTheme, true);
+            }
+
+            // note: we save the theme so that it doesn't suddenly change when
+            // the user disables "use-system-theme" and reloads the page or
+            // navigates to another page
+        }
+    }
+
+    mql.addListener(handlePreferenceChange);
+
+    return function() {
+        handlePreferenceChange(mql);
+    };
+})();
+
+if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia) {
+    // update the preferred dark theme if the user is already using a dark theme
+    // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732
+    if (getCurrentValue("rustdoc-use-system-theme") === null
+        && getCurrentValue("rustdoc-preferred-dark-theme") === null
+        && darkThemes.indexOf(localStoredTheme) >= 0) {
+        updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme);
+    }
+
+    // call the function to initialize the theme at least once!
+    updateSystemTheme();
+} else {
+    switchTheme(
+        currentTheme,
+        mainTheme,
+        getCurrentValue("rustdoc-theme") || "light",
+        false
+    );
+}
diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css
index 3b15b21..d1cddf0 100644
--- a/src/librustdoc/html/static/themes/ayu.css
+++ b/src/librustdoc/html/static/themes/ayu.css
@@ -219,7 +219,8 @@
 }
 
 .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
-.docblock-short a:not(.srclink):not(.test-arrow), .stability a {
+.docblock-short a:not(.srclink):not(.test-arrow), .stability a,
+#help a {
 	color: #39AFD7;
 }
 
@@ -275,6 +276,10 @@
 	border-radius: 4px;
 }
 
+#help > div > span {
+	border-bottom-color: #5c6773;
+}
+
 .since {
 	color: grey;
 }
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index f5a8533..3545943 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -177,7 +177,8 @@
 }
 
 .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
-.docblock-short a:not(.srclink):not(.test-arrow), .stability a {
+.docblock-short a:not(.srclink):not(.test-arrow), .stability a,
+#help a {
 	color: #D2991D;
 }
 
@@ -231,6 +232,10 @@
 	border-color: #bfbfbf;
 }
 
+#help > div > span {
+	border-bottom-color: #bfbfbf;
+}
+
 #help dt {
 	border-color: #bfbfbf;
 	background: rgba(0,0,0,0);
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index 9dea875..4ce4b63 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -175,7 +175,8 @@
 }
 
 .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),
-.docblock-short a:not(.srclink):not(.test-arrow), .stability a {
+.docblock-short a:not(.srclink):not(.test-arrow), .stability a,
+#help a {
 	color: #3873AD;
 }
 
@@ -229,6 +230,10 @@
 	border-color: #bfbfbf;
 }
 
+#help > div > span {
+	border-bottom-color: #bfbfbf;
+}
+
 .since {
 	color: grey;
 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 7762e8f..616f0ef 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -3,11 +3,13 @@
     html_playground_url = "https://play.rust-lang.org/"
 )]
 #![feature(rustc_private)]
+#![feature(array_methods)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(or_patterns)]
+#![feature(peekable_next_if)]
 #![feature(test)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
@@ -83,12 +85,6 @@
 mod visit_ast;
 mod visit_lib;
 
-struct Output {
-    krate: clean::Crate,
-    renderinfo: config::RenderInfo,
-    renderopts: config::RenderOptions,
-}
-
 pub fn main() {
     rustc_driver::set_sigpipe_handler();
     rustc_driver::install_ice_hook();
@@ -519,15 +515,12 @@
 
     krate.version = crate_version;
 
-    let out = Output { krate, renderinfo, renderopts };
-
     if show_coverage {
         // if we ran coverage, bail early, we don't need to also generate docs at this point
         // (also we didn't load in any of the useful passes)
         return Ok(());
     }
 
-    let Output { krate, renderinfo, renderopts } = out;
     info!("going to format");
     let (error_format, edition, debugging_options) = diag_opts;
     let diag = core::new_handler(error_format, None, &debugging_options);
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 671e082..ced26fc 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -1,10 +1,12 @@
 use crate::clean;
-use crate::config::OutputFormat;
 use crate::core::DocContext;
 use crate::fold::{self, DocFolder};
 use crate::html::markdown::{find_testable_code, ErrorCodes};
 use crate::passes::doc_test_lints::{should_have_doc_example, Tests};
 use crate::passes::Pass;
+use rustc_lint::builtin::MISSING_DOCS;
+use rustc_middle::lint::LintSource;
+use rustc_session::lint;
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use serde::Serialize;
@@ -19,10 +21,10 @@
 };
 
 fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate {
-    let mut calc = CoverageCalculator::new();
+    let mut calc = CoverageCalculator::new(ctx);
     let krate = calc.fold_crate(krate);
 
-    calc.print_results(ctx.renderinfo.borrow().output_format);
+    calc.print_results();
 
     krate
 }
@@ -41,8 +43,11 @@
         has_docs: bool,
         has_doc_example: bool,
         should_have_doc_examples: bool,
+        should_have_docs: bool,
     ) {
-        self.total += 1;
+        if has_docs || should_have_docs {
+            self.total += 1;
+        }
 
         if has_docs {
             self.with_docs += 1;
@@ -94,8 +99,9 @@
     }
 }
 
-struct CoverageCalculator {
+struct CoverageCalculator<'a, 'b> {
     items: BTreeMap<FileName, ItemCount>,
+    ctx: &'a DocContext<'b>,
 }
 
 fn limit_filename_len(filename: String) -> String {
@@ -108,9 +114,9 @@
     }
 }
 
-impl CoverageCalculator {
-    fn new() -> CoverageCalculator {
-        CoverageCalculator { items: Default::default() }
+impl<'a, 'b> CoverageCalculator<'a, 'b> {
+    fn new(ctx: &'a DocContext<'b>) -> CoverageCalculator<'a, 'b> {
+        CoverageCalculator { items: Default::default(), ctx }
     }
 
     fn to_json(&self) -> String {
@@ -124,7 +130,8 @@
         .expect("failed to convert JSON data to string")
     }
 
-    fn print_results(&self, output_format: Option<OutputFormat>) {
+    fn print_results(&self) {
+        let output_format = self.ctx.renderinfo.borrow().output_format;
         if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) {
             println!("{}", self.to_json());
             return;
@@ -178,7 +185,7 @@
     }
 }
 
-impl fold::DocFolder for CoverageCalculator {
+impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
     fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
         match i.inner {
             _ if !i.def_id.is_local() => {
@@ -232,7 +239,12 @@
                 let mut tests = Tests { found_tests: 0 };
 
                 find_testable_code(
-                    &i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::<Vec<_>>().join("\n"),
+                    &i.attrs
+                        .doc_strings
+                        .iter()
+                        .map(|d| d.doc.as_str())
+                        .collect::<Vec<_>>()
+                        .join("\n"),
                     &mut tests,
                     ErrorCodes::No,
                     false,
@@ -240,11 +252,18 @@
                 );
 
                 let has_doc_example = tests.found_tests != 0;
+                let hir_id = self.ctx.tcx.hir().local_def_id_to_hir_id(i.def_id.expect_local());
+                let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
+                // `missing_docs` is allow-by-default, so don't treat this as ignoring the item
+                // unless the user had an explicit `allow`
+                let should_have_docs =
+                    level != lint::Level::Allow || matches!(source, LintSource::Default);
                 debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename);
                 self.items.entry(i.source.filename.clone()).or_default().count_item(
                     has_docs,
                     has_doc_example,
-                    should_have_doc_example(&i.inner),
+                    should_have_doc_example(self.ctx, &i),
+                    should_have_docs,
                 );
             }
         }
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
index c218559..c2f7f97 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -1,4 +1,4 @@
-use crate::clean::{self, DocFragment, Item};
+use crate::clean::{self, DocFragment, DocFragmentKind, Item};
 use crate::core::DocContext;
 use crate::fold;
 use crate::fold::DocFolder;
@@ -12,23 +12,6 @@
     description: "concatenates all document attributes into one document attribute",
 };
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum DocFragmentKind {
-    Sugared,
-    Raw,
-    Include,
-}
-
-impl DocFragment {
-    fn kind(&self) -> DocFragmentKind {
-        match *self {
-            DocFragment::SugaredDoc(..) => DocFragmentKind::Sugared,
-            DocFragment::RawDoc(..) => DocFragmentKind::Raw,
-            DocFragment::Include(..) => DocFragmentKind::Include,
-        }
-    }
-}
-
 pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
     let mut krate = Collapser.fold_crate(krate);
     krate.collapsed = true;
@@ -50,30 +33,25 @@
 
     for frag in take(doc_strings) {
         if let Some(mut curr_frag) = last_frag.take() {
-            let curr_kind = curr_frag.kind();
-            let new_kind = frag.kind();
+            let curr_kind = &curr_frag.kind;
+            let new_kind = &frag.kind;
 
-            if curr_kind == DocFragmentKind::Include || curr_kind != new_kind {
-                match curr_frag {
-                    DocFragment::SugaredDoc(_, _, ref mut doc_string)
-                    | DocFragment::RawDoc(_, _, ref mut doc_string) => {
-                        // add a newline for extra padding between segments
-                        doc_string.push('\n');
-                    }
-                    _ => {}
+            if matches!(*curr_kind, DocFragmentKind::Include { .. })
+                || curr_kind != new_kind
+                || curr_frag.parent_module != frag.parent_module
+            {
+                if *curr_kind == DocFragmentKind::SugaredDoc
+                    || *curr_kind == DocFragmentKind::RawDoc
+                {
+                    // add a newline for extra padding between segments
+                    curr_frag.doc.push('\n');
                 }
                 docs.push(curr_frag);
                 last_frag = Some(frag);
             } else {
-                match curr_frag {
-                    DocFragment::SugaredDoc(_, ref mut span, ref mut doc_string)
-                    | DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => {
-                        doc_string.push('\n');
-                        doc_string.push_str(frag.as_str());
-                        *span = span.to(frag.span());
-                    }
-                    _ => unreachable!(),
-                }
+                curr_frag.doc.push('\n');
+                curr_frag.doc.push_str(&frag.doc);
+                curr_frag.span = curr_frag.span.to(frag.span);
                 last_frag = Some(curr_frag);
             }
         } else {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index cd6a7fe..8be9482 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -8,7 +8,7 @@
     Namespace::{self, *},
     PerNS, Res,
 };
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_middle::ty;
 use rustc_resolve::ParentScope;
 use rustc_session::lint::{
@@ -16,6 +16,7 @@
     Lint,
 };
 use rustc_span::hygiene::MacroKind;
+use rustc_span::symbol::sym;
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
@@ -23,6 +24,7 @@
 
 use std::borrow::Cow;
 use std::cell::Cell;
+use std::mem;
 use std::ops::Range;
 
 use crate::clean::*;
@@ -65,10 +67,53 @@
     NotResolved { module_id: DefId, partial_res: Option<Res>, unresolved: Cow<'a, str> },
     /// should not ever happen
     NoParentItem,
+    /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced.
+    MalformedGenerics(MalformedGenerics),
     /// used to communicate that this should be ignored, but shouldn't be reported to the user
     Dummy,
 }
 
+#[derive(Debug)]
+enum MalformedGenerics {
+    /// This link has unbalanced angle brackets.
+    ///
+    /// For example, `Vec<T` should trigger this, as should `Vec<T>>`.
+    UnbalancedAngleBrackets,
+    /// The generics are not attached to a type.
+    ///
+    /// For example, `<T>` should trigger this.
+    ///
+    /// This is detected by checking if the path is empty after the generics are stripped.
+    MissingType,
+    /// The link uses fully-qualified syntax, which is currently unsupported.
+    ///
+    /// For example, `<Vec as IntoIterator>::into_iter` should trigger this.
+    ///
+    /// This is detected by checking if ` as ` (the keyword `as` with spaces around it) is inside
+    /// angle brackets.
+    HasFullyQualifiedSyntax,
+    /// The link has an invalid path separator.
+    ///
+    /// For example, `Vec:<T>:new()` should trigger this. Note that `Vec:new()` will **not**
+    /// trigger this because it has no generics and thus [`strip_generics_from_path`] will not be
+    /// called.
+    ///
+    /// Note that this will also **not** be triggered if the invalid path separator is inside angle
+    /// brackets because rustdoc mostly ignores what's inside angle brackets (except for
+    /// [`HasFullyQualifiedSyntax`](MalformedGenerics::HasFullyQualifiedSyntax)).
+    ///
+    /// This is detected by checking if there is a colon followed by a non-colon in the link.
+    InvalidPathSeparator,
+    /// The link has too many angle brackets.
+    ///
+    /// For example, `Vec<<T>>` should trigger this.
+    TooManyAngleBrackets,
+    /// The link has empty angle brackets.
+    ///
+    /// For example, `Vec<>` should trigger this.
+    EmptyAngleBrackets,
+}
+
 impl ResolutionFailure<'a> {
     // This resolved fully (not just partially) but is erroneous for some other reason
     fn full_res(&self) -> Option<Res> {
@@ -190,6 +235,56 @@
         }
     }
 
+    fn resolve_primitive_associated_item(
+        &self,
+        prim_ty: hir::PrimTy,
+        ns: Namespace,
+        module_id: DefId,
+        item_name: Symbol,
+        item_str: &'path str,
+    ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
+        let cx = self.cx;
+
+        PrimitiveType::from_hir(prim_ty)
+            .impls(cx.tcx)
+            .into_iter()
+            .find_map(|&impl_| {
+                cx.tcx
+                    .associated_items(impl_)
+                    .find_by_name_and_namespace(
+                        cx.tcx,
+                        Ident::with_dummy_span(item_name),
+                        ns,
+                        impl_,
+                    )
+                    .map(|item| match item.kind {
+                        ty::AssocKind::Fn => "method",
+                        ty::AssocKind::Const => "associatedconstant",
+                        ty::AssocKind::Type => "associatedtype",
+                    })
+                    .map(|out| {
+                        (
+                            Res::PrimTy(prim_ty),
+                            Some(format!("{}#{}.{}", prim_ty.name(), out, item_str)),
+                        )
+                    })
+            })
+            .ok_or_else(|| {
+                debug!(
+                    "returning primitive error for {}::{} in {} namespace",
+                    prim_ty.name(),
+                    item_name,
+                    ns.descr()
+                );
+                ResolutionFailure::NotResolved {
+                    module_id,
+                    partial_res: Some(Res::PrimTy(prim_ty)),
+                    unresolved: item_str.into(),
+                }
+                .into()
+            })
+    }
+
     /// Resolves a string as a macro.
     fn macro_resolve(
         &self,
@@ -231,6 +326,19 @@
         })
     }
 
+    fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
+        let result = self.cx.enter_resolver(|resolver| {
+            resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+        });
+        debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
+        match result.map(|(_, res)| res) {
+            // resolver doesn't know about true and false so we'll have to resolve them
+            // manually as bool
+            Ok(Res::Err) | Err(()) => is_bool_value(path_str, ns).map(|(_, res)| res),
+            Ok(res) => Some(res.map_id(|_| panic!("unexpected node_id"))),
+        }
+    }
+
     /// Resolves a string as a path within a particular namespace. Also returns an optional
     /// URL fragment in the case of variants and methods.
     fn resolve<'path>(
@@ -243,22 +351,18 @@
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let cx = self.cx;
 
-        let result = cx.enter_resolver(|resolver| {
-            resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
-        });
-        debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
-        let result = match result {
-            Ok((_, Res::Err)) => Err(()),
-            x => x,
-        };
-
-        if let Ok((_, res)) = result {
-            let res = res.map_id(|_| panic!("unexpected node_id"));
-            // In case this is a trait item, skip the
-            // early return and try looking for the trait.
-            let value = match res {
-                Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true,
-                Res::Def(DefKind::AssocTy, _) => false,
+        if let Some(res) = self.resolve_path(path_str, ns, module_id) {
+            match res {
+                Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => {
+                    assert_eq!(ns, ValueNS);
+                    // Fall through: In case this is a trait item, skip the
+                    // early return and try looking for the trait.
+                }
+                Res::Def(DefKind::AssocTy, _) => {
+                    assert_eq!(ns, TypeNS);
+                    // Fall through: In case this is a trait item, skip the
+                    // early return and try looking for the trait.
+                }
                 Res::Def(DefKind::Variant, _) => {
                     return handle_variant(cx, res, extra_fragment);
                 }
@@ -277,17 +381,7 @@
                 _ => {
                     return Ok((res, extra_fragment.clone()));
                 }
-            };
-
-            if value != (ns == ValueNS) {
-                return Err(ResolutionFailure::WrongNamespace(res, ns).into());
             }
-        // FIXME: why is this necessary?
-        } else if let Some((path, prim)) = is_primitive(path_str, ns) {
-            if extra_fragment.is_some() {
-                return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim)));
-            }
-            return Ok((prim, Some(path.to_owned())));
         }
 
         // Try looking for methods and associated items.
@@ -315,70 +409,30 @@
                 }
             })?;
 
-        if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
-            let impls =
-                primitive_impl(cx, &path).ok_or_else(|| ResolutionFailure::NotResolved {
+        // FIXME: are these both necessary?
+        let ty_res = if let Some(ty_res) = is_primitive(&path_root, TypeNS)
+            .map(|(_, res)| res)
+            .or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
+        {
+            ty_res
+        } else {
+            // FIXME: this is duplicated on the end of this function.
+            return if ns == Namespace::ValueNS {
+                self.variant_field(path_str, current_item, module_id)
+            } else {
+                Err(ResolutionFailure::NotResolved {
                     module_id,
-                    partial_res: Some(prim),
-                    unresolved: item_str.into(),
-                })?;
-            for &impl_ in impls {
-                let link = cx
-                    .tcx
-                    .associated_items(impl_)
-                    .find_by_name_and_namespace(
-                        cx.tcx,
-                        Ident::with_dummy_span(item_name),
-                        ns,
-                        impl_,
-                    )
-                    .map(|item| match item.kind {
-                        ty::AssocKind::Fn => "method",
-                        ty::AssocKind::Const => "associatedconstant",
-                        ty::AssocKind::Type => "associatedtype",
-                    })
-                    .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str))));
-                if let Some(link) = link {
-                    return Ok(link);
+                    partial_res: None,
+                    unresolved: path_root.into(),
                 }
-            }
-            debug!(
-                "returning primitive error for {}::{} in {} namespace",
-                path,
-                item_name,
-                ns.descr()
-            );
-            return Err(ResolutionFailure::NotResolved {
-                module_id,
-                partial_res: Some(prim),
-                unresolved: item_str.into(),
-            }
-            .into());
-        }
-
-        let ty_res = cx
-            .enter_resolver(|resolver| {
-                // only types can have associated items
-                resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id)
-            })
-            .map(|(_, res)| res);
-        let ty_res = match ty_res {
-            Err(()) | Ok(Res::Err) => {
-                return if ns == Namespace::ValueNS {
-                    self.variant_field(path_str, current_item, module_id)
-                } else {
-                    Err(ResolutionFailure::NotResolved {
-                        module_id,
-                        partial_res: None,
-                        unresolved: path_root.into(),
-                    }
-                    .into())
-                };
-            }
-            Ok(res) => res,
+                .into())
+            };
         };
-        let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
+
         let res = match ty_res {
+            Res::PrimTy(prim) => Some(
+                self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
+            ),
             Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => {
                 debug!("looking for associated item named {} for item {:?}", item_name, did);
                 // Checks if item_name belongs to `impl SomeItem`
@@ -418,7 +472,7 @@
                     Some(if extra_fragment.is_some() {
                         Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
                     } else {
-                        // HACK(jynelson): `clean` expects the type, not the associated item.
+                        // HACK(jynelson): `clean` expects the type, not the associated item
                         // but the disambiguator logic expects the associated item.
                         // Store the kind in a side channel so that only the disambiguator logic looks at it.
                         self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
@@ -464,13 +518,7 @@
                         _ => None,
                     }
                 } else {
-                    // We already know this isn't in ValueNS, so no need to check variant_field
-                    return Err(ResolutionFailure::NotResolved {
-                        module_id,
-                        partial_res: Some(ty_res),
-                        unresolved: item_str.into(),
-                    }
-                    .into());
+                    None
                 }
             }
             Res::Def(DefKind::Trait, did) => cx
@@ -527,30 +575,21 @@
         current_item: &Option<String>,
         extra_fragment: &Option<String>,
     ) -> Option<Res> {
-        let check_full_res_inner = |this: &Self, result: Result<Res, ErrorKind<'_>>| {
-            let res = match result {
-                Ok(res) => Some(res),
-                Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
-                Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => {
-                    Some(res)
-                }
-                Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None,
-            };
-            this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res)
+        // resolve() can't be used for macro namespace
+        let result = match ns {
+            Namespace::MacroNS => self.macro_resolve(path_str, module_id).map_err(ErrorKind::from),
+            Namespace::TypeNS | Namespace::ValueNS => self
+                .resolve(path_str, ns, current_item, module_id, extra_fragment)
+                .map(|(res, _)| res),
         };
-        // cannot be used for macro namespace
-        let check_full_res = |this: &Self, ns| {
-            let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment);
-            check_full_res_inner(this, result.map(|(res, _)| res))
+
+        let res = match result {
+            Ok(res) => Some(res),
+            Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
+            Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res),
+            Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None,
         };
-        let check_full_res_macro = |this: &Self| {
-            let result = this.macro_resolve(path_str, module_id);
-            check_full_res_inner(this, result.map_err(ErrorKind::from))
-        };
-        match ns {
-            Namespace::MacroNS => check_full_res_macro(self),
-            Namespace::TypeNS | Namespace::ValueNS => check_full_res(self, ns),
-        }
+        self.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res)
     }
 }
 
@@ -650,14 +689,9 @@
     let ty = cx.tcx.type_of(type_);
     let iter = in_scope_traits.iter().flat_map(|&trait_| {
         trace!("considering explicit impl for trait {:?}", trait_);
-        let mut saw_impl = false;
-        // Look at each trait implementation to see if it's an impl for `did`
-        cx.tcx.for_each_relevant_impl(trait_, ty, |impl_| {
-            // FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long
-            if saw_impl {
-                return;
-            }
 
+        // Look at each trait implementation to see if it's an impl for `did`
+        cx.tcx.find_map_relevant_impl(trait_, ty, |impl_| {
             let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
             // Check if these are the same type.
             let impl_type = trait_ref.self_ty();
@@ -668,7 +702,7 @@
                 type_
             );
             // Fast path: if this is a primitive simple `==` will work
-            saw_impl = impl_type == ty
+            let saw_impl = impl_type == ty
                 || match impl_type.kind() {
                     // Check if these are the same def_id
                     ty::Adt(def, _) => {
@@ -678,8 +712,9 @@
                     ty::Foreign(def_id) => *def_id == type_,
                     _ => false,
                 };
-        });
-        if saw_impl { Some(trait_) } else { None }
+
+            if saw_impl { Some(trait_) } else { None }
+        })
     });
     iter.collect()
 }
@@ -758,7 +793,7 @@
                 debug!("ignoring extern crate item {:?}", item.def_id);
                 return self.fold_item_recur(item);
             }
-            ImportItem(Import::Simple(ref name, ..)) => Some(name.clone()),
+            ImportItem(Import { kind: ImportKind::Simple(ref name, ..), .. }) => Some(name.clone()),
             MacroItem(..) => None,
             _ => item.name.clone(),
         };
@@ -767,9 +802,6 @@
             self.mod_ids.push(item.def_id);
         }
 
-        let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
-        trace!("got documentation '{}'", dox);
-
         // find item's parent to resolve `Self` in item's docs below
         let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| {
             let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
@@ -807,16 +839,53 @@
             }
         });
 
-        for (ori_link, link_range) in markdown_links(&dox) {
-            self.resolve_link(
-                &mut item,
-                &dox,
-                &current_item,
-                parent_node,
-                &parent_name,
-                ori_link,
-                link_range,
-            );
+        // We want to resolve in the lexical scope of the documentation.
+        // In the presence of re-exports, this is not the same as the module of the item.
+        // Rather than merging all documentation into one, resolve it one attribute at a time
+        // so we know which module it came from.
+        let mut attrs = item.attrs.doc_strings.iter().peekable();
+        while let Some(attr) = attrs.next() {
+            // `collapse_docs` does not have the behavior we want:
+            // we want `///` and `#[doc]` to count as the same attribute,
+            // but currently it will treat them as separate.
+            // As a workaround, combine all attributes with the same parent module into the same attribute.
+            let mut combined_docs = attr.doc.clone();
+            loop {
+                match attrs.peek() {
+                    Some(next) if next.parent_module == attr.parent_module => {
+                        combined_docs.push('\n');
+                        combined_docs.push_str(&attrs.next().unwrap().doc);
+                    }
+                    _ => break,
+                }
+            }
+            debug!("combined_docs={}", combined_docs);
+
+            let (krate, parent_node) = if let Some(id) = attr.parent_module {
+                trace!("docs {:?} came from {:?}", attr.doc, id);
+                (id.krate, Some(id))
+            } else {
+                trace!("no parent found for {:?}", attr.doc);
+                (item.def_id.krate, parent_node)
+            };
+            // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
+            // This is a degenerate case and it's not supported by rustdoc.
+            // FIXME: this will break links that start in `#[doc = ...]` and end as a sugared doc. Should this be supported?
+            for (ori_link, link_range) in markdown_links(&combined_docs) {
+                let link = self.resolve_link(
+                    &item,
+                    &combined_docs,
+                    &current_item,
+                    parent_node,
+                    &parent_name,
+                    krate,
+                    ori_link,
+                    link_range,
+                );
+                if let Some(link) = link {
+                    item.attrs.links.push(link);
+                }
+            }
         }
 
         if item.is_mod() && !item.attrs.inner_docs {
@@ -838,24 +907,25 @@
 impl LinkCollector<'_, '_> {
     fn resolve_link(
         &self,
-        item: &mut Item,
+        item: &Item,
         dox: &str,
         current_item: &Option<String>,
         parent_node: Option<DefId>,
         parent_name: &Option<String>,
+        krate: CrateNum,
         ori_link: String,
         link_range: Option<Range<usize>>,
-    ) {
+    ) -> Option<ItemLink> {
         trace!("considering link '{}'", ori_link);
 
         // Bail early for real links.
         if ori_link.contains('/') {
-            return;
+            return None;
         }
 
         // [] is mostly likely not supposed to be a link
         if ori_link.is_empty() {
-            return;
+            return None;
         }
 
         let cx = self.cx;
@@ -863,11 +933,11 @@
         let parts = link.split('#').collect::<Vec<_>>();
         let (link, extra_fragment) = if parts.len() > 2 {
             anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors);
-            return;
+            return None;
         } else if parts.len() == 2 {
             if parts[0].trim().is_empty() {
                 // This is an anchor to an element of the current page, nothing to do in here!
-                return;
+                return None;
             }
             (parts[0], Some(parts[1].to_owned()))
         } else {
@@ -877,6 +947,7 @@
         let link_text;
         let mut path_str;
         let disambiguator;
+        let stripped_path_string;
         let (mut res, mut fragment) = {
             path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
                 disambiguator = Some(d);
@@ -887,8 +958,8 @@
             }
             .trim();
 
-            if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) {
-                return;
+            if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) {
+                return None;
             }
 
             // We stripped `()` and `!` when parsing the disambiguator.
@@ -914,7 +985,7 @@
                 parent_node
             };
 
-            let module_id = if let Some(id) = base_node {
+            let mut module_id = if let Some(id) = base_node {
                 id
             } else {
                 debug!("attempting to resolve item without parent module: {}", path_str);
@@ -928,7 +999,7 @@
                     link_range,
                     smallvec![err_kind],
                 );
-                return;
+                return None;
             };
 
             // replace `Self` with suitable item's parent name
@@ -937,6 +1008,47 @@
                     resolved_self = format!("{}::{}", name, &path_str[6..]);
                     path_str = &resolved_self;
                 }
+            } else if path_str.starts_with("crate::") {
+                use rustc_span::def_id::CRATE_DEF_INDEX;
+
+                // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented.
+                // But rustdoc wants it to mean the crate this item was originally present in.
+                // To work around this, remove it and resolve relative to the crate root instead.
+                // HACK(jynelson)(2): If we just strip `crate::` then suddenly primitives become ambiguous
+                // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root.
+                resolved_self = format!("self::{}", &path_str["crate::".len()..]);
+                path_str = &resolved_self;
+                module_id = DefId { krate, index: CRATE_DEF_INDEX };
+            }
+
+            // Strip generics from the path.
+            if path_str.contains(['<', '>'].as_slice()) {
+                stripped_path_string = match strip_generics_from_path(path_str) {
+                    Ok(path) => path,
+                    Err(err_kind) => {
+                        debug!("link has malformed generics: {}", path_str);
+                        resolution_failure(
+                            self,
+                            &item,
+                            path_str,
+                            disambiguator,
+                            dox,
+                            link_range,
+                            smallvec![err_kind],
+                        );
+                        return None;
+                    }
+                };
+                path_str = &stripped_path_string;
+            }
+
+            // Sanity check to make sure we don't have any angle brackets after stripping generics.
+            assert!(!path_str.contains(['<', '>'].as_slice()));
+
+            // The link is not an intra-doc link if it still contains commas or spaces after
+            // stripping generics.
+            if path_str.contains([',', ' '].as_slice()) {
+                return None;
             }
 
             match self.resolve_with_disambiguator(
@@ -951,7 +1063,7 @@
                 link_range.clone(),
             ) {
                 Some(x) => x,
-                None => return,
+                None => return None,
             }
         };
 
@@ -975,15 +1087,15 @@
                             link_range,
                             AnchorFailure::RustdocAnchorConflict(prim),
                         );
-                        return;
+                        return None;
                     }
                     res = prim;
-                    fragment = Some(path.to_owned());
+                    fragment = Some(path.as_str().to_string());
                 } else {
                     // `[char]` when a `char` module is in scope
                     let candidates = vec![res, prim];
                     ambiguity_error(cx, &item, path_str, dox, link_range, candidates);
-                    return;
+                    return None;
                 }
             }
         }
@@ -1007,16 +1119,11 @@
         if let Res::PrimTy(..) = res {
             match disambiguator {
                 Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
-                    item.attrs.links.push(ItemLink {
-                        link: ori_link,
-                        link_text,
-                        did: None,
-                        fragment,
-                    });
+                    Some(ItemLink { link: ori_link, link_text, did: None, fragment })
                 }
                 Some(other) => {
                     report_mismatch(other, Disambiguator::Primitive);
-                    return;
+                    None
                 }
             }
         } else {
@@ -1039,7 +1146,7 @@
                     (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
                     (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
                         report_mismatch(specified, Disambiguator::Kind(kind));
-                        return;
+                        return None;
                     }
                 }
             }
@@ -1062,14 +1169,14 @@
                 }
             }
             let id = register_res(cx, res);
-            item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment });
+            Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment })
         }
     }
 
     fn resolve_with_disambiguator(
         &self,
         disambiguator: Option<Disambiguator>,
-        item: &mut Item,
+        item: &Item,
         dox: &str,
         path_str: &str,
         current_item: &Option<String>,
@@ -1565,22 +1672,27 @@
                     };
                     // See if this was a module: `[path]` or `[std::io::nope]`
                     if let Some(module) = last_found_module {
-                        let module_name = collector.cx.tcx.item_name(module);
-                        let note = format!(
-                            "the module `{}` contains no item named `{}`",
-                            module_name, unresolved
-                        );
+                        let note = if partial_res.is_some() {
+                            // Part of the link resolved; e.g. `std::io::nonexistent`
+                            let module_name = collector.cx.tcx.item_name(module);
+                            format!("no item named `{}` in module `{}`", unresolved, module_name)
+                        } else {
+                            // None of the link resolved; e.g. `Notimported`
+                            format!("no item named `{}` in scope", unresolved)
+                        };
                         if let Some(span) = sp {
                             diag.span_label(span, &note);
                         } else {
                             diag.note(&note);
                         }
+
                         // If the link has `::` in it, assume it was meant to be an intra-doc link.
                         // Otherwise, the `[]` might be unrelated.
                         // FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links
                         if !path_str.contains("::") {
                             diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
                         }
+
                         continue;
                     }
 
@@ -1672,6 +1784,27 @@
                         diag.level = rustc_errors::Level::Bug;
                         "all intra doc links should have a parent item".to_owned()
                     }
+                    ResolutionFailure::MalformedGenerics(variant) => match variant {
+                        MalformedGenerics::UnbalancedAngleBrackets => {
+                            String::from("unbalanced angle brackets")
+                        }
+                        MalformedGenerics::MissingType => {
+                            String::from("missing type for generic parameters")
+                        }
+                        MalformedGenerics::HasFullyQualifiedSyntax => {
+                            diag.note("see https://github.com/rust-lang/rust/issues/74563 for more information");
+                            String::from("fully-qualified syntax is unsupported")
+                        }
+                        MalformedGenerics::InvalidPathSeparator => {
+                            String::from("has invalid path separator")
+                        }
+                        MalformedGenerics::TooManyAngleBrackets => {
+                            String::from("too many angle brackets")
+                        }
+                        MalformedGenerics::EmptyAngleBrackets => {
+                            String::from("empty angle brackets")
+                        }
+                    },
                 };
                 if let Some(span) = sp {
                     diag.span_label(span, &note);
@@ -1814,51 +1947,158 @@
     if extra_fragment.is_some() {
         return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)));
     }
-    let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) {
-        parent
-    } else {
-        return Err(ResolutionFailure::NoParentItem.into());
-    };
-    let parent_def = Res::Def(DefKind::Enum, parent);
-    let variant = cx.tcx.expect_variant_res(res);
-    Ok((parent_def, Some(format!("variant.{}", variant.ident.name))))
+    cx.tcx
+        .parent(res.def_id())
+        .map(|parent| {
+            let parent_def = Res::Def(DefKind::Enum, parent);
+            let variant = cx.tcx.expect_variant_res(res);
+            (parent_def, Some(format!("variant.{}", variant.ident.name)))
+        })
+        .ok_or_else(|| ResolutionFailure::NoParentItem.into())
 }
 
-const PRIMITIVES: &[(&str, Res)] = &[
-    ("u8", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))),
-    ("u16", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))),
-    ("u32", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))),
-    ("u64", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))),
-    ("u128", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))),
-    ("usize", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))),
-    ("i8", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))),
-    ("i16", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))),
-    ("i32", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))),
-    ("i64", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))),
-    ("i128", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))),
-    ("isize", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))),
-    ("f32", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))),
-    ("f64", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
-    ("str", Res::PrimTy(hir::PrimTy::Str)),
-    ("bool", Res::PrimTy(hir::PrimTy::Bool)),
-    ("true", Res::PrimTy(hir::PrimTy::Bool)),
-    ("false", Res::PrimTy(hir::PrimTy::Bool)),
-    ("char", Res::PrimTy(hir::PrimTy::Char)),
+// FIXME: At this point, this is basically a copy of the PrimitiveTypeTable
+const PRIMITIVES: &[(Symbol, Res)] = &[
+    (sym::u8, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))),
+    (sym::u16, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))),
+    (sym::u32, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))),
+    (sym::u64, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))),
+    (sym::u128, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))),
+    (sym::usize, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))),
+    (sym::i8, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))),
+    (sym::i16, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))),
+    (sym::i32, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))),
+    (sym::i64, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))),
+    (sym::i128, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))),
+    (sym::isize, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))),
+    (sym::f32, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))),
+    (sym::f64, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
+    (sym::str, Res::PrimTy(hir::PrimTy::Str)),
+    (sym::bool, Res::PrimTy(hir::PrimTy::Bool)),
+    (sym::char, Res::PrimTy(hir::PrimTy::Char)),
 ];
 
-fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> {
-    if ns == TypeNS {
-        PRIMITIVES
-            .iter()
-            .filter(|x| x.0 == path_str)
-            .copied()
-            .map(|x| if x.0 == "true" || x.0 == "false" { ("bool", x.1) } else { x })
-            .next()
+fn is_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
+    is_bool_value(path_str, ns).or_else(|| {
+        if ns == TypeNS {
+            // FIXME: this should be replaced by a lookup in PrimitiveTypeTable
+            let maybe_primitive = Symbol::intern(path_str);
+            PRIMITIVES.iter().find(|x| x.0 == maybe_primitive).copied()
+        } else {
+            None
+        }
+    })
+}
+
+fn is_bool_value(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
+    if ns == TypeNS && (path_str == "true" || path_str == "false") {
+        Some((sym::bool, Res::PrimTy(hir::PrimTy::Bool)))
     } else {
         None
     }
 }
 
-fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<&'static SmallVec<[DefId; 4]>> {
-    Some(PrimitiveType::from_symbol(Symbol::intern(path_str))?.impls(cx.tcx))
+fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> {
+    let mut stripped_segments = vec![];
+    let mut path = path_str.chars().peekable();
+    let mut segment = Vec::new();
+
+    while let Some(chr) = path.next() {
+        match chr {
+            ':' => {
+                if path.next_if_eq(&':').is_some() {
+                    let stripped_segment =
+                        strip_generics_from_path_segment(mem::take(&mut segment))?;
+                    if !stripped_segment.is_empty() {
+                        stripped_segments.push(stripped_segment);
+                    }
+                } else {
+                    return Err(ResolutionFailure::MalformedGenerics(
+                        MalformedGenerics::InvalidPathSeparator,
+                    ));
+                }
+            }
+            '<' => {
+                segment.push(chr);
+
+                match path.next() {
+                    Some('<') => {
+                        return Err(ResolutionFailure::MalformedGenerics(
+                            MalformedGenerics::TooManyAngleBrackets,
+                        ));
+                    }
+                    Some('>') => {
+                        return Err(ResolutionFailure::MalformedGenerics(
+                            MalformedGenerics::EmptyAngleBrackets,
+                        ));
+                    }
+                    Some(chr) => {
+                        segment.push(chr);
+
+                        while let Some(chr) = path.next_if(|c| *c != '>') {
+                            segment.push(chr);
+                        }
+                    }
+                    None => break,
+                }
+            }
+            _ => segment.push(chr),
+        }
+        debug!("raw segment: {:?}", segment);
+    }
+
+    if !segment.is_empty() {
+        let stripped_segment = strip_generics_from_path_segment(segment)?;
+        if !stripped_segment.is_empty() {
+            stripped_segments.push(stripped_segment);
+        }
+    }
+
+    debug!("path_str: {:?}\nstripped segments: {:?}", path_str, &stripped_segments);
+
+    let stripped_path = stripped_segments.join("::");
+
+    if !stripped_path.is_empty() {
+        Ok(stripped_path)
+    } else {
+        Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::MissingType))
+    }
+}
+
+fn strip_generics_from_path_segment(
+    segment: Vec<char>,
+) -> Result<String, ResolutionFailure<'static>> {
+    let mut stripped_segment = String::new();
+    let mut param_depth = 0;
+
+    let mut latest_generics_chunk = String::new();
+
+    for c in segment {
+        if c == '<' {
+            param_depth += 1;
+            latest_generics_chunk.clear();
+        } else if c == '>' {
+            param_depth -= 1;
+            if latest_generics_chunk.contains(" as ") {
+                // The segment tries to use fully-qualified syntax, which is currently unsupported.
+                // Give a helpful error message instead of completely ignoring the angle brackets.
+                return Err(ResolutionFailure::MalformedGenerics(
+                    MalformedGenerics::HasFullyQualifiedSyntax,
+                ));
+            }
+        } else {
+            if param_depth == 0 {
+                stripped_segment.push(c);
+            } else {
+                latest_generics_chunk.push(c);
+            }
+        }
+    }
+
+    if param_depth == 0 {
+        Ok(stripped_segment)
+    } else {
+        // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>`
+        Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::UnbalancedAngleBrackets))
+    }
 }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index b2c4c30..5eb3f98b 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -30,7 +30,7 @@
     for &cnum in cx.tcx.crates().iter() {
         for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
             cx.tcx.sess.time("build_extern_trait_impl", || {
-                inline::build_impl(cx, did, None, &mut new_items);
+                inline::build_impl(cx, None, did, None, &mut new_items);
             });
         }
     }
@@ -38,7 +38,7 @@
     // Also try to inline primitive impls from other crates.
     for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
         if !def_id.is_local() {
-            inline::build_impl(cx, def_id, None, &mut new_items);
+            inline::build_impl(cx, None, def_id, None, &mut new_items);
 
             // FIXME(eddyb) is this `doc(hidden)` check needed?
             if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
@@ -90,7 +90,7 @@
         for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
             let impl_did = cx.tcx.hir().local_def_id(impl_node);
             cx.tcx.sess.time("build_local_trait_impl", || {
-                inline::build_impl(cx, impl_did.to_def_id(), None, &mut new_items);
+                inline::build_impl(cx, None, impl_did.to_def_id(), None, &mut new_items);
             });
         }
     }
diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs
index 78af9f9..686ec51 100644
--- a/src/librustdoc/passes/doc_test_lints.rs
+++ b/src/librustdoc/passes/doc_test_lints.rs
@@ -9,6 +9,7 @@
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
+use rustc_middle::lint::LintSource;
 use rustc_session::lint;
 
 pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
@@ -56,8 +57,8 @@
     }
 }
 
-pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool {
-    !matches!(item_kind,
+pub fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
+    if matches!(item.inner,
         clean::StructFieldItem(_)
         | clean::VariantItem(_)
         | clean::AssocConstItem(_, _)
@@ -69,7 +70,13 @@
         | clean::ImportItem(_)
         | clean::PrimitiveItem(_)
         | clean::KeywordItem(_)
-    )
+    ) {
+        return false;
+    }
+    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local());
+    let (level, source) =
+        cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id);
+    level != lint::Level::Allow || matches!(source, LintSource::Default)
 }
 
 pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
@@ -88,7 +95,7 @@
     if tests.found_tests == 0
         && rustc_feature::UnstableFeatures::from_environment().is_nightly_build()
     {
-        if should_have_doc_example(&item.inner) {
+        if should_have_doc_example(cx, &item) {
             debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
             let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
             cx.tcx.struct_span_lint_hir(
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
new file mode 100644
index 0000000..1d9be61
--- /dev/null
+++ b/src/librustdoc/passes/html_tags.rs
@@ -0,0 +1,226 @@
+use super::{span_of_attrs, Pass};
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::html::markdown::opts;
+use core::ops::Range;
+use pulldown_cmark::{Event, Parser};
+use rustc_feature::UnstableFeatures;
+use rustc_session::lint;
+use std::iter::Peekable;
+use std::str::CharIndices;
+
+pub const CHECK_INVALID_HTML_TAGS: Pass = Pass {
+    name: "check-invalid-html-tags",
+    run: check_invalid_html_tags,
+    description: "detects invalid HTML tags in doc comments",
+};
+
+struct InvalidHtmlTagsLinter<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
+}
+
+impl<'a, 'tcx> InvalidHtmlTagsLinter<'a, 'tcx> {
+    fn new(cx: &'a DocContext<'tcx>) -> Self {
+        InvalidHtmlTagsLinter { cx }
+    }
+}
+
+pub fn check_invalid_html_tags(krate: Crate, cx: &DocContext<'_>) -> Crate {
+    if !UnstableFeatures::from_environment().is_nightly_build() {
+        krate
+    } else {
+        let mut coll = InvalidHtmlTagsLinter::new(cx);
+
+        coll.fold_crate(krate)
+    }
+}
+
+const ALLOWED_UNCLOSED: &[&str] = &[
+    "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
+    "source", "track", "wbr",
+];
+
+fn drop_tag(
+    tags: &mut Vec<(String, Range<usize>)>,
+    tag_name: String,
+    range: Range<usize>,
+    f: &impl Fn(&str, &Range<usize>),
+) {
+    let tag_name_low = tag_name.to_lowercase();
+    if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) {
+        // If the tag is nested inside a "<script>" or a "<style>" tag, no warning should
+        // be emitted.
+        let should_not_warn = tags.iter().take(pos + 1).any(|(at, _)| {
+            let at = at.to_lowercase();
+            at == "script" || at == "style"
+        });
+        for (last_tag_name, last_tag_span) in tags.drain(pos + 1..) {
+            if should_not_warn {
+                continue;
+            }
+            let last_tag_name_low = last_tag_name.to_lowercase();
+            if ALLOWED_UNCLOSED.iter().any(|&at| at == &last_tag_name_low) {
+                continue;
+            }
+            // `tags` is used as a queue, meaning that everything after `pos` is included inside it.
+            // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still
+            // have `h3`, meaning the tag wasn't closed as it should have.
+            f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span);
+        }
+        // Remove the `tag_name` that was originally closed
+        tags.pop();
+    } else {
+        // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required
+        // but it helps for the visualization).
+        f(&format!("unopened HTML tag `{}`", tag_name), &range);
+    }
+}
+
+fn extract_html_tag(
+    tags: &mut Vec<(String, Range<usize>)>,
+    text: &str,
+    range: &Range<usize>,
+    start_pos: usize,
+    iter: &mut Peekable<CharIndices<'_>>,
+    f: &impl Fn(&str, &Range<usize>),
+) {
+    let mut tag_name = String::new();
+    let mut is_closing = false;
+    let mut prev_pos = start_pos;
+
+    loop {
+        let (pos, c) = match iter.peek() {
+            Some((pos, c)) => (*pos, *c),
+            // In case we reached the of the doc comment, we want to check that it's an
+            // unclosed HTML tag. For example "/// <h3".
+            None => (prev_pos, '\0'),
+        };
+        prev_pos = pos;
+        // Checking if this is a closing tag (like `</a>` for `<a>`).
+        if c == '/' && tag_name.is_empty() {
+            is_closing = true;
+        } else if c.is_ascii_alphanumeric() {
+            tag_name.push(c);
+        } else {
+            if !tag_name.is_empty() {
+                let mut r = Range { start: range.start + start_pos, end: range.start + pos };
+                if c == '>' {
+                    // In case we have a tag without attribute, we can consider the span to
+                    // refer to it fully.
+                    r.end += 1;
+                }
+                if is_closing {
+                    // In case we have "</div >" or even "</div         >".
+                    if c != '>' {
+                        if !c.is_whitespace() {
+                            // It seems like it's not a valid HTML tag.
+                            break;
+                        }
+                        let mut found = false;
+                        for (new_pos, c) in text[pos..].char_indices() {
+                            if !c.is_whitespace() {
+                                if c == '>' {
+                                    r.end = range.start + new_pos + 1;
+                                    found = true;
+                                }
+                                break;
+                            }
+                        }
+                        if !found {
+                            break;
+                        }
+                    }
+                    drop_tag(tags, tag_name, r, f);
+                } else {
+                    tags.push((tag_name, r));
+                }
+            }
+            break;
+        }
+        iter.next();
+    }
+}
+
+fn extract_tags(
+    tags: &mut Vec<(String, Range<usize>)>,
+    text: &str,
+    range: Range<usize>,
+    is_in_comment: &mut Option<Range<usize>>,
+    f: &impl Fn(&str, &Range<usize>),
+) {
+    let mut iter = text.char_indices().peekable();
+
+    while let Some((start_pos, c)) = iter.next() {
+        if is_in_comment.is_some() {
+            if text[start_pos..].starts_with("-->") {
+                *is_in_comment = None;
+            }
+        } else if c == '<' {
+            if text[start_pos..].starts_with("<!--") {
+                // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!)
+                iter.next();
+                iter.next();
+                iter.next();
+                *is_in_comment = Some(Range {
+                    start: range.start + start_pos,
+                    end: range.start + start_pos + 3,
+                });
+            } else {
+                extract_html_tag(tags, text, &range, start_pos, &mut iter, f);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
+    fn fold_item(&mut self, item: Item) -> Option<Item> {
+        let hir_id = match self.cx.as_local_hir_id(item.def_id) {
+            Some(hir_id) => hir_id,
+            None => {
+                // If non-local, no need to check anything.
+                return self.fold_item_recur(item);
+            }
+        };
+        let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
+        if !dox.is_empty() {
+            let cx = &self.cx;
+            let report_diag = |msg: &str, range: &Range<usize>| {
+                let sp = match super::source_span_for_markdown_range(cx, &dox, range, &item.attrs) {
+                    Some(sp) => sp,
+                    None => span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
+                };
+                cx.tcx.struct_span_lint_hir(lint::builtin::INVALID_HTML_TAGS, hir_id, sp, |lint| {
+                    lint.build(msg).emit()
+                });
+            };
+
+            let mut tags = Vec::new();
+            let mut is_in_comment = None;
+
+            let p = Parser::new_ext(&dox, opts()).into_offset_iter();
+
+            for (event, range) in p {
+                match event {
+                    Event::Html(text) | Event::Text(text) => {
+                        extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag)
+                    }
+                    _ => {}
+                }
+            }
+
+            for (tag, range) in tags.iter().filter(|(t, _)| {
+                let t = t.to_lowercase();
+                ALLOWED_UNCLOSED.iter().find(|&&at| at == t).is_none()
+            }) {
+                report_diag(&format!("unclosed HTML tag `{}`", tag), range);
+            }
+
+            if let Some(range) = is_in_comment {
+                report_diag("Unclosed HTML comment", &range);
+            }
+        }
+
+        self.fold_item_recur(item)
+    }
+}
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 75a6596..2591650 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -1,16 +1,15 @@
 //! Contains information about "passes", used to modify crate information during the documentation
 //! process.
 
-use rustc_hir::def_id::{DefId, DefIdSet};
-use rustc_middle::middle::privacy::AccessLevels;
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
-use std::mem;
 use std::ops::Range;
 
 use self::Condition::*;
-use crate::clean::{self, GetDefId, Item};
+use crate::clean::{self, DocFragmentKind};
 use crate::core::DocContext;
-use crate::fold::{DocFolder, StripItem};
+
+mod stripper;
+pub use stripper::*;
 
 mod collapse_docs;
 pub use self::collapse_docs::COLLAPSE_DOCS;
@@ -45,6 +44,9 @@
 mod calculate_doc_coverage;
 pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
 
+mod html_tags;
+pub use self::html_tags::CHECK_INVALID_HTML_TAGS;
+
 /// A single pass over the cleaned documentation.
 ///
 /// Runs in the compiler context, so it has access to types and traits and the like.
@@ -87,6 +89,7 @@
     CHECK_CODE_BLOCK_SYNTAX,
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
+    CHECK_INVALID_HTML_TAGS,
 ];
 
 /// The list of passes run by default.
@@ -100,6 +103,7 @@
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
     ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
+    ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
 ];
 
@@ -144,181 +148,16 @@
     PASSES.iter().find(|p| p.name == pass_name).copied()
 }
 
-struct Stripper<'a> {
-    retained: &'a mut DefIdSet,
-    access_levels: &'a AccessLevels<DefId>,
-    update_retained: bool,
-}
-
-impl<'a> DocFolder for Stripper<'a> {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.inner {
-            clean::StrippedItem(..) => {
-                // We need to recurse into stripped modules to strip things
-                // like impl methods but when doing so we must not add any
-                // items to the `retained` set.
-                debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
-                let old = mem::replace(&mut self.update_retained, false);
-                let ret = self.fold_item_recur(i);
-                self.update_retained = old;
-                return ret;
-            }
-            // These items can all get re-exported
-            clean::OpaqueTyItem(..)
-            | clean::TypedefItem(..)
-            | clean::StaticItem(..)
-            | clean::StructItem(..)
-            | clean::EnumItem(..)
-            | clean::TraitItem(..)
-            | clean::FunctionItem(..)
-            | clean::VariantItem(..)
-            | clean::MethodItem(..)
-            | clean::ForeignFunctionItem(..)
-            | clean::ForeignStaticItem(..)
-            | clean::ConstantItem(..)
-            | clean::UnionItem(..)
-            | clean::AssocConstItem(..)
-            | clean::TraitAliasItem(..)
-            | clean::ForeignTypeItem => {
-                if i.def_id.is_local() {
-                    if !self.access_levels.is_exported(i.def_id) {
-                        debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
-                        return None;
-                    }
-                }
-            }
-
-            clean::StructFieldItem(..) => {
-                if i.visibility != clean::Public {
-                    return StripItem(i).strip();
-                }
-            }
-
-            clean::ModuleItem(..) => {
-                if i.def_id.is_local() && i.visibility != clean::Public {
-                    debug!("Stripper: stripping module {:?}", i.name);
-                    let old = mem::replace(&mut self.update_retained, false);
-                    let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
-                    self.update_retained = old;
-                    return ret;
-                }
-            }
-
-            // handled in the `strip-priv-imports` pass
-            clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
-
-            clean::ImplItem(..) => {}
-
-            // tymethods/macros have no control over privacy
-            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
-
-            // Proc-macros are always public
-            clean::ProcMacroItem(..) => {}
-
-            // Primitives are never stripped
-            clean::PrimitiveItem(..) => {}
-
-            // Associated types are never stripped
-            clean::AssocTypeItem(..) => {}
-
-            // Keywords are never stripped
-            clean::KeywordItem(..) => {}
-        }
-
-        let fastreturn = match i.inner {
-            // nothing left to do for traits (don't want to filter their
-            // methods out, visibility controlled by the trait)
-            clean::TraitItem(..) => true,
-
-            // implementations of traits are always public.
-            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
-            // Struct variant fields have inherited visibility
-            clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true,
-            _ => false,
-        };
-
-        let i = if fastreturn {
-            if self.update_retained {
-                self.retained.insert(i.def_id);
-            }
-            return Some(i);
-        } else {
-            self.fold_item_recur(i)
-        };
-
-        if let Some(ref i) = i {
-            if self.update_retained {
-                self.retained.insert(i.def_id);
-            }
-        }
-        i
-    }
-}
-
-// This stripper discards all impls which reference stripped items
-struct ImplStripper<'a> {
-    retained: &'a DefIdSet,
-}
-
-impl<'a> DocFolder for ImplStripper<'a> {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if let clean::ImplItem(ref imp) = i.inner {
-            // emptied none trait impls can be stripped
-            if imp.trait_.is_none() && imp.items.is_empty() {
-                return None;
-            }
-            if let Some(did) = imp.for_.def_id() {
-                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
-                    debug!("ImplStripper: impl item for stripped type; removing");
-                    return None;
-                }
-            }
-            if let Some(did) = imp.trait_.def_id() {
-                if did.is_local() && !self.retained.contains(&did) {
-                    debug!("ImplStripper: impl item for stripped trait; removing");
-                    return None;
-                }
-            }
-            if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
-                for typaram in generics {
-                    if let Some(did) = typaram.def_id() {
-                        if did.is_local() && !self.retained.contains(&did) {
-                            debug!(
-                                "ImplStripper: stripped item in trait's generics; removing impl"
-                            );
-                            return None;
-                        }
-                    }
-                }
-            }
-        }
-        self.fold_item_recur(i)
-    }
-}
-
-// This stripper discards all private import statements (`use`, `extern crate`)
-struct ImportStripper;
-impl DocFolder for ImportStripper {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.inner {
-            clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => {
-                None
-            }
-            _ => self.fold_item_recur(i),
-        }
-    }
-}
-
 /// Returns a span encompassing all the given attributes.
 crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> {
     if attrs.doc_strings.is_empty() {
         return None;
     }
-    let start = attrs.doc_strings[0].span();
+    let start = attrs.doc_strings[0].span;
     if start == DUMMY_SP {
         return None;
     }
-    let end = attrs.doc_strings.last().expect("no doc strings provided").span();
+    let end = attrs.doc_strings.last().expect("no doc strings provided").span;
     Some(start.to(end))
 }
 
@@ -333,10 +172,8 @@
     md_range: &Range<usize>,
     attrs: &clean::Attributes,
 ) -> Option<Span> {
-    let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag {
-        clean::DocFragment::SugaredDoc(..) => true,
-        _ => false,
-    });
+    let is_all_sugared_doc =
+        attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
 
     if !is_all_sugared_doc {
         return None;
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
new file mode 100644
index 0000000..9b4f622
--- /dev/null
+++ b/src/librustdoc/passes/stripper.rs
@@ -0,0 +1,172 @@
+use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_middle::middle::privacy::AccessLevels;
+use std::mem;
+
+use crate::clean::{self, GetDefId, Item};
+use crate::fold::{DocFolder, StripItem};
+
+pub struct Stripper<'a> {
+    pub retained: &'a mut DefIdSet,
+    pub access_levels: &'a AccessLevels<DefId>,
+    pub update_retained: bool,
+}
+
+impl<'a> DocFolder for Stripper<'a> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::StrippedItem(..) => {
+                // We need to recurse into stripped modules to strip things
+                // like impl methods but when doing so we must not add any
+                // items to the `retained` set.
+                debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
+                let old = mem::replace(&mut self.update_retained, false);
+                let ret = self.fold_item_recur(i);
+                self.update_retained = old;
+                return ret;
+            }
+            // These items can all get re-exported
+            clean::OpaqueTyItem(..)
+            | clean::TypedefItem(..)
+            | clean::StaticItem(..)
+            | clean::StructItem(..)
+            | clean::EnumItem(..)
+            | clean::TraitItem(..)
+            | clean::FunctionItem(..)
+            | clean::VariantItem(..)
+            | clean::MethodItem(..)
+            | clean::ForeignFunctionItem(..)
+            | clean::ForeignStaticItem(..)
+            | clean::ConstantItem(..)
+            | clean::UnionItem(..)
+            | clean::AssocConstItem(..)
+            | clean::TraitAliasItem(..)
+            | clean::ForeignTypeItem => {
+                if i.def_id.is_local() {
+                    if !self.access_levels.is_exported(i.def_id) {
+                        debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
+                        return None;
+                    }
+                }
+            }
+
+            clean::StructFieldItem(..) => {
+                if i.visibility != clean::Public {
+                    return StripItem(i).strip();
+                }
+            }
+
+            clean::ModuleItem(..) => {
+                if i.def_id.is_local() && i.visibility != clean::Public {
+                    debug!("Stripper: stripping module {:?}", i.name);
+                    let old = mem::replace(&mut self.update_retained, false);
+                    let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
+                    self.update_retained = old;
+                    return ret;
+                }
+            }
+
+            // handled in the `strip-priv-imports` pass
+            clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
+
+            clean::ImplItem(..) => {}
+
+            // tymethods/macros have no control over privacy
+            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
+
+            // Proc-macros are always public
+            clean::ProcMacroItem(..) => {}
+
+            // Primitives are never stripped
+            clean::PrimitiveItem(..) => {}
+
+            // Associated types are never stripped
+            clean::AssocTypeItem(..) => {}
+
+            // Keywords are never stripped
+            clean::KeywordItem(..) => {}
+        }
+
+        let fastreturn = match i.inner {
+            // nothing left to do for traits (don't want to filter their
+            // methods out, visibility controlled by the trait)
+            clean::TraitItem(..) => true,
+
+            // implementations of traits are always public.
+            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
+            // Struct variant fields have inherited visibility
+            clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true,
+            _ => false,
+        };
+
+        let i = if fastreturn {
+            if self.update_retained {
+                self.retained.insert(i.def_id);
+            }
+            return Some(i);
+        } else {
+            self.fold_item_recur(i)
+        };
+
+        if let Some(ref i) = i {
+            if self.update_retained {
+                self.retained.insert(i.def_id);
+            }
+        }
+        i
+    }
+}
+
+/// This stripper discards all impls which reference stripped items
+pub struct ImplStripper<'a> {
+    pub retained: &'a DefIdSet,
+}
+
+impl<'a> DocFolder for ImplStripper<'a> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        if let clean::ImplItem(ref imp) = i.inner {
+            // emptied none trait impls can be stripped
+            if imp.trait_.is_none() && imp.items.is_empty() {
+                return None;
+            }
+            if let Some(did) = imp.for_.def_id() {
+                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
+                    debug!("ImplStripper: impl item for stripped type; removing");
+                    return None;
+                }
+            }
+            if let Some(did) = imp.trait_.def_id() {
+                if did.is_local() && !self.retained.contains(&did) {
+                    debug!("ImplStripper: impl item for stripped trait; removing");
+                    return None;
+                }
+            }
+            if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
+                for typaram in generics {
+                    if let Some(did) = typaram.def_id() {
+                        if did.is_local() && !self.retained.contains(&did) {
+                            debug!(
+                                "ImplStripper: stripped item in trait's generics; removing impl"
+                            );
+                            return None;
+                        }
+                    }
+                }
+            }
+        }
+        self.fold_item_recur(i)
+    }
+}
+
+/// This stripper discards all private import statements (`use`, `extern crate`)
+pub struct ImportStripper;
+
+impl DocFolder for ImportStripper {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => {
+                None
+            }
+            _ => self.fold_item_recur(i),
+        }
+    }
+}
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index 5604a9c..a9cf5a8 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -36,13 +36,7 @@
 
 fn unindent_fragments(docs: &mut Vec<DocFragment>) {
     for fragment in docs {
-        match *fragment {
-            DocFragment::SugaredDoc(_, _, ref mut doc_string)
-            | DocFragment::RawDoc(_, _, ref mut doc_string)
-            | DocFragment::Include(_, _, _, ref mut doc_string) => {
-                *doc_string = unindent(doc_string)
-            }
-        }
+        fragment.doc = unindent(&fragment.doc);
     }
 }
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 33578dc..cbfd219 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -399,6 +399,7 @@
                 om.extern_crates.push(ExternCrate {
                     cnum: self.cx.tcx.extern_mod_stmt_cnum(def_id).unwrap_or(LOCAL_CRATE),
                     name: ident.name,
+                    hir_id: item.hir_id,
                     path: orig_name.map(|x| x.to_string()),
                     vis: &item.vis,
                     attrs: &item.attrs,
diff --git a/src/llvm-project b/src/llvm-project
index 7075196..655a146 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 7075196da1aa3527f7c87943607e25f3cf24997a
+Subproject commit 655a1467c98741e332b87661a9046877077ef4dc
diff --git a/src/stage0.txt b/src/stage0.txt
index f695b75..9eaa58d 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.(x+1).0` for Cargo where they were released on `date`.
 
-date: 2020-08-26
+date: 2020-10-16
 rustc: beta
 cargo: beta
 
@@ -20,7 +20,7 @@
 # bootstrapping issues with use of new syntax in this repo. If you're looking at
 # the beta/stable branch, this key should be omitted, as we don't want to depend
 # on rustfmt from nightly there.
-rustfmt: nightly-2020-07-12
+rustfmt: nightly-2020-10-12
 
 # When making a stable release the process currently looks like:
 #
diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs
index b195ed8..04e840d 100644
--- a/src/test/assembly/asm/mips-types.rs
+++ b/src/test/assembly/asm/mips-types.rs
@@ -1,6 +1,8 @@
 // no-system-llvm
+// revisions: mips32 mips64
 // assembly-output: emit-asm
-// compile-flags: --target mips-unknown-linux-gnu
+//[mips32] compile-flags: --target mips-unknown-linux-gnu
+//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
 // needs-llvm-components: mips
 
 #![feature(no_core, lang_items, rustc_attrs, repr_simd)]
@@ -32,7 +34,9 @@
 impl Copy for u8 {}
 impl Copy for i16 {}
 impl Copy for i32 {}
+impl Copy for i64 {}
 impl Copy for f32 {}
+impl Copy for f64 {}
 impl Copy for ptr {}
 extern "C" {
     fn extern_func();
@@ -44,148 +48,190 @@
     fn dont_merge(s: &str);
 }
 
-macro_rules! check { ($func:ident, $ty:ty, $class:ident) => {
+macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => {
     #[no_mangle]
     pub unsafe fn $func(x: $ty) -> $ty {
         dont_merge(stringify!($func));
 
         let y;
-        asm!("move {}, {}", out($class) y, in($class) x);
+        asm!(concat!($mov," {}, {}"), out($class) y, in($class) x);
         y
     }
 };}
 
-macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt) => {
+macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => {
     #[no_mangle]
     pub unsafe fn $func(x: $ty) -> $ty {
         dont_merge(stringify!($func));
 
         let y;
-        asm!(concat!("move ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
+        asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
         y
     }
 };}
 
-// CHECK-LABEL: sym_static:
-// CHECK: #APP
-// CHECK: lw $3, %got(extern_static)
-// CHECK: #NO_APP
+// mips32-LABEL: sym_static_32:
+// mips32: #APP
+// mips32: lw $3, %got(extern_static)
+// mips32: #NO_APP
+#[cfg(mips32)]
 #[no_mangle]
-pub unsafe fn sym_static() {
-    dont_merge(stringify!($func));
-
-    asm!("la $v1, {}", sym extern_static);
+pub unsafe fn sym_static_32() {
+    asm!("lw $v1, {}", sym extern_static);
 }
 
-// CHECK-LABEL: sym_fn:
-// CHECK: #APP
-// CHECK: lw $3, %got(extern_func)
-// CHECK: #NO_APP
+// mips32-LABEL: sym_fn_32:
+// mips32: #APP
+// mips32: lw $3, %got(extern_func)
+// mips32: #NO_APP
+#[cfg(mips32)]
 #[no_mangle]
-pub unsafe fn sym_fn() {
-    dont_merge(stringify!($func));
+pub unsafe fn sym_fn_32() {
+    asm!("lw $v1, {}", sym extern_func);
+}
 
-    asm!("la $v1, {}", sym extern_func);
+// mips64-LABEL: sym_static_64:
+// mips64: #APP
+// mips64: ld $3, %got_disp(extern_static)
+// mips64: #NO_APP
+#[cfg(mips64)]
+#[no_mangle]
+pub unsafe fn sym_static_64() {
+    asm!("ld $v1, {}", sym extern_static);
+}
+
+// mips64-LABEL: sym_fn_64:
+// mips64: #APP
+// mips64: ld $3, %got_disp(extern_func)
+// mips64: #NO_APP
+#[cfg(mips64)]
+#[no_mangle]
+pub unsafe fn sym_fn_64() {
+    asm!("ld $v1, {}", sym extern_func);
 }
 
 // CHECK-LABEL: reg_f32:
 // CHECK: #APP
 // CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}}
 // CHECK: #NO_APP
-#[no_mangle]
-pub unsafe fn reg_f32(x: f32) -> f32 {
-    dont_merge("reg_f32");
-    let y;
-    asm!("mov.s {}, {}", out(freg) y, in(freg) x);
-    y
-}
+check!(reg_f32, f32, freg, "mov.s");
 
 // CHECK-LABEL: f0_f32:
 // CHECK: #APP
 // CHECK: mov.s $f0, $f0
 // CHECK: #NO_APP
 #[no_mangle]
-pub unsafe fn f0_f32(x: f32) -> f32 {
-    dont_merge("f0_f32");
-    let y;
-    asm!("mov.s $f0, $f0", lateout("$f0") y, in("$f0") x);
-    y
-}
+check_reg!(f0_f32, f32, "$f0", "mov.s");
+
+// CHECK-LABEL: reg_f32_64:
+// CHECK: #APP
+// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_f32_64, f32, freg, "mov.d");
+
+// CHECK-LABEL: f0_f32_64:
+// CHECK: #APP
+// CHECK: mov.d $f0, $f0
+// CHECK: #NO_APP
+#[no_mangle]
+check_reg!(f0_f32_64, f32, "$f0", "mov.d");
+
+// CHECK-LABEL: reg_f64:
+// CHECK: #APP
+// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}}
+// CHECK: #NO_APP
+#[no_mangle]
+check!(reg_f64, f64, freg, "mov.d");
+
+// CHECK-LABEL: f0_f64:
+// CHECK: #APP
+// CHECK: mov.d $f0, $f0
+// CHECK: #NO_APP
+#[no_mangle]
+check_reg!(f0_f64, f64, "$f0", "mov.d");
 
 // CHECK-LABEL: reg_ptr:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_ptr, ptr, reg);
+check!(reg_ptr, ptr, reg, "move");
 
 // CHECK-LABEL: reg_i32:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_i32, i32, reg);
+check!(reg_i32, i32, reg, "move");
 
 // CHECK-LABEL: reg_f32_soft:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_f32_soft, f32, reg);
+check!(reg_f32_soft, f32, reg, "move");
+
+// mips64-LABEL: reg_f64_soft:
+// mips64: #APP
+// mips64: move ${{[0-9]+}}, ${{[0-9]+}}
+// mips64: #NO_APP
+#[cfg(mips64)]
+check!(reg_f64_soft, f64, reg, "move");
 
 // CHECK-LABEL: reg_i8:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_i8, i8, reg);
+check!(reg_i8, i8, reg, "move");
 
 // CHECK-LABEL: reg_u8:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_u8, u8, reg);
+check!(reg_u8, u8, reg, "move");
 
 // CHECK-LABEL: reg_i16:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_i16, i16, reg);
+check!(reg_i16, i16, reg, "move");
 
-// CHECK-LABEL: t0_ptr:
+// mips64-LABEL: reg_i64:
+// mips64: #APP
+// mips64: move ${{[0-9]+}}, ${{[0-9]+}}
+// mips64: #NO_APP
+#[cfg(mips64)]
+check!(reg_i64, i64, reg, "move");
+
+// CHECK-LABEL: r8_ptr:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_ptr, ptr, "$t0");
+check_reg!(r8_ptr, ptr, "$8", "move");
 
-// CHECK-LABEL: t0_i32:
+// CHECK-LABEL: r8_i32:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_i32, i32, "$t0");
+check_reg!(r8_i32, i32, "$8", "move");
 
-// CHECK-LABEL: t0_f32:
+// CHECK-LABEL: r8_f32:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_f32, f32, "$t0");
+check_reg!(r8_f32, f32, "$8", "move");
 
-// CHECK-LABEL: t0_i8:
+// CHECK-LABEL: r8_i8:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_i8, i8, "$t0");
+check_reg!(r8_i8, i8, "$8", "move");
 
-// CHECK-LABEL: t0_u8:
+// CHECK-LABEL: r8_u8:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_u8, u8, "$t0");
-
-// CHECK-LABEL: t0_i16:
-// CHECK: #APP
-// CHECK: move $8, $8
-// CHECK: #NO_APP
-check_reg!(t0_i16, i16, "$t0");
+check_reg!(r8_u8, u8, "$8", "move");
 
 // CHECK-LABEL: r8_i16:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(r8_i16, i16, "$8");
+check_reg!(r8_i16, i16, "$8", "move");
diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs
index 0c7f3bb..99a7914 100644
--- a/src/test/codegen/drop.rs
+++ b/src/test/codegen/drop.rs
@@ -23,13 +23,13 @@
 // FIXME(eddyb) the `void @` forces a match on the instruction, instead of the
 // comment, that's `; call core::intrinsics::drop_in_place::<drop::SomeUniqueName>`
 // for the `v0` mangling, should switch to matching on that once `legacy` is gone.
+// CHECK-NOT: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
 // CHECK-NOT: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
 // CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
 // CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
-// CHECK-NOT: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
-// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
 // CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
-// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
 // CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
 // CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
 // The next line checks for the } that ends the function definition
diff --git a/src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs b/src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs
new file mode 100644
index 0000000..d07eaa7
--- /dev/null
+++ b/src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs
@@ -0,0 +1,18 @@
+// This test checks that bounds checks are elided when
+// index is part of a (x | y) < C style condition
+
+// min-llvm-version: 11.0.0
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @get
+#[no_mangle]
+pub fn get(array: &[u8; 8], x: usize, y: usize) -> u8 {
+    if x > 7 || y > 7 {
+        0
+    } else {
+        // CHECK-NOT: panic_bounds_check
+        array[y]
+    }
+}
diff --git a/src/test/codegen/issue-75659.rs b/src/test/codegen/issue-75659.rs
new file mode 100644
index 0000000..d093c84
--- /dev/null
+++ b/src/test/codegen/issue-75659.rs
@@ -0,0 +1,63 @@
+// This test checks that the call to memchr/slice_contains is optimized away
+// when searching in small slices.
+
+// compile-flags: -O
+// only-x86_64
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @foo1
+#[no_mangle]
+pub fn foo1(x: u8, data: &[u8; 1]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo2
+#[no_mangle]
+pub fn foo2(x: u8, data: &[u8; 2]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo3
+#[no_mangle]
+pub fn foo3(x: u8, data: &[u8; 3]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo4
+#[no_mangle]
+pub fn foo4(x: u8, data: &[u8; 4]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo8
+#[no_mangle]
+pub fn foo8(x: u8, data: &[u8; 8]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    data.contains(&x)
+}
+
+// CHECK-LABEL: @foo8_i8
+#[no_mangle]
+pub fn foo8_i8(x: i8, data: &[i8; 8]) -> bool {
+    // CHECK-NOT: memchr
+    // CHECK-NOT: slice_contains
+    !data.contains(&x)
+}
+
+// Check that the general case isn't inlined
+// CHECK-LABEL: @foo80
+#[no_mangle]
+pub fn foo80(x: u8, data: &[u8; 80]) -> bool {
+    // CHECK: call core::slice::memchr
+    data.contains(&x)
+}
diff --git a/src/test/codegen/loop.rs b/src/test/codegen/loop.rs
new file mode 100644
index 0000000..e54298e
--- /dev/null
+++ b/src/test/codegen/loop.rs
@@ -0,0 +1,15 @@
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @check_loop
+#[no_mangle]
+pub fn check_loop() -> u8 {
+    // CHECK-NOT: unreachable
+    call_looper()
+}
+
+#[no_mangle]
+fn call_looper() -> ! {
+    loop {}
+}
diff --git a/src/test/codegen/slice-windows-no-bounds-check.rs b/src/test/codegen/slice-windows-no-bounds-check.rs
new file mode 100644
index 0000000..4f5f442
--- /dev/null
+++ b/src/test/codegen/slice-windows-no-bounds-check.rs
@@ -0,0 +1,35 @@
+#![crate_type = "lib"]
+
+// compile-flags: -O
+
+use std::slice::Windows;
+
+// CHECK-LABEL: @naive_string_search
+#[no_mangle]
+pub fn naive_string_search(haystack: &str, needle: &str) -> Option<usize> {
+    if needle.is_empty() {
+        return Some(0);
+    }
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    haystack
+        .as_bytes()
+        .windows(needle.len())
+        .position(|sub| sub == needle.as_bytes())
+}
+
+// CHECK-LABEL: @next
+#[no_mangle]
+pub fn next<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> {
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    w.next()
+}
+
+// CHECK-LABEL: @next_back
+#[no_mangle]
+pub fn next_back<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> {
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    w.next_back()
+}
diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs
index 30e7adf..d30b706 100644
--- a/src/test/codegen/try_identity.rs
+++ b/src/test/codegen/try_identity.rs
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=2
+// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=2 -Zunsound-mir-opts
 
 // Ensure that `x?` has no overhead on `Result<T, E>` due to identity `match`es in lowering.
 // This requires inlining to trigger the MIR optimizations in `SimplifyArmIdentity`.
diff --git a/src/test/codegen/tune-cpu-on-functions.rs b/src/test/codegen/tune-cpu-on-functions.rs
new file mode 100644
index 0000000..9121799
--- /dev/null
+++ b/src/test/codegen/tune-cpu-on-functions.rs
@@ -0,0 +1,21 @@
+// This test makes sure that functions get annotated with the proper
+// "tune-cpu" attribute in LLVM.
+
+// no-prefer-dynamic
+// ignore-tidy-linelength
+// compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic
+
+#![crate_type = "staticlib"]
+
+// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0
+#[no_mangle]
+pub extern fn exported() {
+    not_exported();
+}
+
+// CHECK-LABEL: ; tune_cpu_on_functions::not_exported
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define {{.*}}() {{.*}} #0
+fn not_exported() {}
+
+// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}"
diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs
index 6447487..68a4d41 100644
--- a/src/test/compile-fail/consts/const-fn-error.rs
+++ b/src/test/compile-fail/consts/const-fn-error.rs
@@ -6,6 +6,8 @@
     let mut sum = 0;
     for i in 0..x {
         //~^ ERROR mutable references
+        //~| ERROR calls in constant functions
+        //~| ERROR calls in constant functions
         //~| ERROR E0080
         //~| ERROR E0744
         sum += i;
diff --git a/src/test/compile-fail/issue-27675-unchecked-bounds.rs b/src/test/compile-fail/issue-27675-unchecked-bounds.rs
new file mode 100644
index 0000000..1cfc230
--- /dev/null
+++ b/src/test/compile-fail/issue-27675-unchecked-bounds.rs
@@ -0,0 +1,19 @@
+/// The compiler previously did not properly check the bound of `From` when it was used from type
+/// of the dyn trait object (use in `copy_any` below). Since the associated type is under user
+/// control in this usage, the compiler could be tricked to believe any type implemented any trait.
+/// This would ICE, except for pure marker traits like `Copy`. It did not require providing an
+/// instance of the dyn trait type, only name said type.
+trait Setup {
+    type From: Copy;
+}
+
+fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+    *from
+}
+
+pub fn copy_any<T>(t: &T) -> T {
+    copy::<dyn Setup<From=T>>(t)
+    //~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs
index a4fbff5..cc2a3a3 100644
--- a/src/test/debuginfo/pretty-std-collections.rs
+++ b/src/test/debuginfo/pretty-std-collections.rs
@@ -34,17 +34,26 @@
 // gdb-check:$6 = BTreeMap(size=15) = {[0] = pretty_std_collections::MyLeafNode (0), [...]}
 // (abbreviated because it's boring but we need enough elements to include internal nodes)
 
+// gdb-command: print zst_key_btree_map
+// gdb-check:$7 = BTreeMap(size=1) = {[()] = 1}
+
+// gdb-command: print zst_val_btree_map
+// gdb-check:$8 = BTreeMap(size=1) = {[1] = ()}
+
+// gdb-command: print zst_key_val_btree_map
+// gdb-check:$9 = BTreeMap(size=1) = {[()] = ()}
+
 // gdb-command: print vec_deque
-// gdb-check:$7 = VecDeque(size=3) = {5, 3, 7}
+// gdb-check:$10 = VecDeque(size=3) = {5, 3, 7}
 
 // gdb-command: print vec_deque2
-// gdb-check:$8 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8}
+// gdb-check:$11 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8}
 
 // gdb-command: print hash_map
-// gdb-check:$9 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40}
+// gdb-check:$12 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40}
 
 // gdb-command: print hash_set
-// gdb-check:$10 = HashSet(size=4) = {1, 2, 3, 4}
+// gdb-check:$13 = HashSet(size=4) = {1, 2, 3, 4}
 
 // === LLDB TESTS ==================================================================================
 
@@ -69,9 +78,9 @@
 #![allow(unused_variables)]
 use std::collections::BTreeMap;
 use std::collections::BTreeSet;
-use std::collections::VecDeque;
 use std::collections::HashMap;
 use std::collections::HashSet;
+use std::collections::VecDeque;
 use std::hash::{BuildHasherDefault, Hasher};
 
 struct MyLeafNode(i32); // helps to ensure we don't blindly replace substring "LeafNode"
@@ -111,6 +120,15 @@
         nasty_btree_map.insert(i, MyLeafNode(i));
     }
 
+    let mut zst_key_btree_map: BTreeMap<(), i32> = BTreeMap::new();
+    zst_key_btree_map.insert((), 1);
+
+    let mut zst_val_btree_map: BTreeMap<i32, ()> = BTreeMap::new();
+    zst_val_btree_map.insert(1, ());
+
+    let mut zst_key_val_btree_map: BTreeMap<(), ()> = BTreeMap::new();
+    zst_key_val_btree_map.insert((), ());
+
     // VecDeque
     let mut vec_deque = VecDeque::new();
     vec_deque.push_back(5);
diff --git a/src/test/incremental/issue-54242.rs b/src/test/incremental/issue-54242.rs
index 25dc7cd..9e449de 100644
--- a/src/test/incremental/issue-54242.rs
+++ b/src/test/incremental/issue-54242.rs
@@ -1,6 +1,9 @@
 // revisions: rpass cfail
 
-trait Tr {
+trait Tr
+where
+    (Self::Arr,): Sized,
+{
     type Arr;
 
     const C: usize = 0;
diff --git a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs
index 8160f8f..5fe435d 100644
--- a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs
+++ b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs
@@ -33,7 +33,9 @@
 
     #[cfg(not(cfail1))]
     pub fn inlined_fn() -> u32 {
-        1234
+        // See `cgu_keeps_identical_fn.rs` for why this is different
+        // from the other version of this function.
+        12345
     }
 }
 
diff --git a/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs
new file mode 100644
index 0000000..0fd5abe
--- /dev/null
+++ b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs
@@ -0,0 +1,47 @@
+// This test is almost identical to `cgu_invalided_via_import`, except that
+// the two versions of `inline_fn` are identical. Neither version of `inlined_fn`
+// ends up with any spans in its LLVM bitecode, so LLVM is able to skip
+// re-building any modules which import 'inlined_fn'
+
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph -O
+// build-pass (FIXME(62277): could be check-pass?)
+
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo",
+                            cfg="cfail2",
+                            kind="no")]
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo",
+                            cfg="cfail3",
+                            kind="post-lto")]
+
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar",
+                            cfg="cfail2",
+                            kind="post-lto")]
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar",
+                            cfg="cfail3",
+                            kind="post-lto")]
+
+mod foo {
+
+    // Trivial functions like this one are imported very reliably by ThinLTO.
+    #[cfg(cfail1)]
+    pub fn inlined_fn() -> u32 {
+        1234
+    }
+
+    #[cfg(not(cfail1))]
+    pub fn inlined_fn() -> u32 {
+        1234
+    }
+}
+
+pub mod bar {
+    use foo::inlined_fn;
+
+    pub fn caller() -> u32 {
+        inlined_fn()
+    }
+}
diff --git a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
index 24e5d24..045f201 100644
--- a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
+++ b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
@@ -37,7 +37,9 @@
 
     #[cfg(not(cfail1))]
     pub fn inlined_fn() -> u32 {
-        1234
+        // See `cgu_keeps_identical_fn.rs` for why this is different
+        // from the other version of this function.
+        12345
     }
 }
 
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
index 2216c2b..deb5dba 100644
--- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
+++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
@@ -48,7 +48,7 @@
         _7 = _2;                         // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8
         _8 = Len(_1);                    // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
         _9 = Lt(_7, _8);                 // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
-        assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
     }
 
     bb2: {
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
index 2216c2b..deb5dba 100644
--- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
+++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
@@ -48,7 +48,7 @@
         _7 = _2;                         // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8
         _8 = Len(_1);                    // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
         _9 = Lt(_7, _8);                 // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
-        assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9
     }
 
     bb2: {
diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
index 5032625..7e0ca3d 100644
--- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
+++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
@@ -41,44 +41,44 @@
         StorageLive(_5);                 // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15
         StorageLive(_6);                 // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20
         _6 = move _4;                    // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20
-        replace(_5 <- move _6) -> [return: bb2, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11
+        replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/basic_assignment.rs:10:1: 24:2
+    bb1: {
+        drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20
     }
 
     bb2: {
-        drop(_6) -> [return: bb6, unwind: bb4]; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20
-    }
-
-    bb3 (cleanup): {
-        drop(_4) -> bb1;                 // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2
-    }
-
-    bb4 (cleanup): {
-        drop(_5) -> bb3;                 // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2
-    }
-
-    bb5 (cleanup): {
-        drop(_6) -> bb4;                 // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20
-    }
-
-    bb6: {
         StorageDead(_6);                 // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20
         _0 = const ();                   // scope 0 at $DIR/basic_assignment.rs:10:11: 24:2
-        drop(_5) -> [return: bb7, unwind: bb3]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2
+        drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2
     }
 
-    bb7: {
+    bb3: {
         StorageDead(_5);                 // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2
-        drop(_4) -> [return: bb8, unwind: bb1]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2
+        drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2
     }
 
-    bb8: {
+    bb4: {
         StorageDead(_4);                 // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2
         StorageDead(_2);                 // scope 1 at $DIR/basic_assignment.rs:24:1: 24:2
         StorageDead(_1);                 // scope 0 at $DIR/basic_assignment.rs:24:1: 24:2
         return;                          // scope 0 at $DIR/basic_assignment.rs:24:2: 24:2
     }
+
+    bb5 (cleanup): {
+        drop(_6) -> bb6;                 // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20
+    }
+
+    bb6 (cleanup): {
+        drop(_5) -> bb7;                 // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2
+    }
+
+    bb7 (cleanup): {
+        drop(_4) -> bb8;                 // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2
+    }
+
+    bb8 (cleanup): {
+        resume;                          // scope 0 at $DIR/basic_assignment.rs:10:1: 24:2
+    }
 }
diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir
index 408efb4..cfbd3a5 100644
--- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir
@@ -14,53 +14,53 @@
         StorageLive(_1);                 // scope 0 at $DIR/box_expr.rs:7:9: 7:10
         StorageLive(_2);                 // scope 0 at $DIR/box_expr.rs:7:13: 7:25
         _2 = Box(S);                     // scope 0 at $DIR/box_expr.rs:7:13: 7:25
-        (*_2) = S::new() -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25
+        (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25
                                          // mir::Constant
                                          // + span: $DIR/box_expr.rs:7:17: 7:23
                                          // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/box_expr.rs:6:1: 9:2
+    bb1: {
+        _1 = move _2;                    // scope 0 at $DIR/box_expr.rs:7:13: 7:25
+        drop(_2) -> bb2;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
     }
 
     bb2: {
-        _1 = move _2;                    // scope 0 at $DIR/box_expr.rs:7:13: 7:25
-        drop(_2) -> bb4;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
-    }
-
-    bb3 (cleanup): {
-        drop(_2) -> bb1;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
-    }
-
-    bb4: {
         StorageDead(_2);                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
         StorageLive(_3);                 // scope 1 at $DIR/box_expr.rs:8:5: 8:12
         StorageLive(_4);                 // scope 1 at $DIR/box_expr.rs:8:10: 8:11
         _4 = move _1;                    // scope 1 at $DIR/box_expr.rs:8:10: 8:11
-        _3 = std::mem::drop::<Box<S>>(move _4) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
+        _3 = std::mem::drop::<Box<S>>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
                                          // mir::Constant
                                          // + span: $DIR/box_expr.rs:8:5: 8:9
                                          // + literal: Const { ty: fn(std::boxed::Box<S>) {std::mem::drop::<std::boxed::Box<S>>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb5: {
+    bb3: {
         StorageDead(_4);                 // scope 1 at $DIR/box_expr.rs:8:11: 8:12
         StorageDead(_3);                 // scope 1 at $DIR/box_expr.rs:8:12: 8:13
         _0 = const ();                   // scope 0 at $DIR/box_expr.rs:6:11: 9:2
-        drop(_1) -> bb8;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+        drop(_1) -> bb4;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
     }
 
-    bb6 (cleanup): {
-        drop(_1) -> bb1;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+    bb4: {
+        StorageDead(_1);                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+        return;                          // scope 0 at $DIR/box_expr.rs:9:2: 9:2
     }
 
-    bb7 (cleanup): {
+    bb5 (cleanup): {
         drop(_4) -> bb6;                 // scope 1 at $DIR/box_expr.rs:8:11: 8:12
     }
 
-    bb8: {
-        StorageDead(_1);                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
-        return;                          // scope 0 at $DIR/box_expr.rs:9:2: 9:2
+    bb6 (cleanup): {
+        drop(_1) -> bb8;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+    }
+
+    bb7 (cleanup): {
+        drop(_2) -> bb8;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+    }
+
+    bb8 (cleanup): {
+        resume;                          // scope 0 at $DIR/box_expr.rs:6:1: 9:2
     }
 }
diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff
index 61e987c..979e5bc 100644
--- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff
+++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff
@@ -32,7 +32,7 @@
 -         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
 +         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
           _5 = Lt(_3, _4);                 // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
-          assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
+          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
       }
   
       bb1: {
@@ -44,7 +44,7 @@
 -         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
 +         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
           _9 = Lt(_7, _8);                 // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
-          assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
+          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
       }
   
       bb2: {
diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff
index 61e987c..979e5bc 100644
--- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff
+++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff
@@ -32,7 +32,7 @@
 -         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
 +         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
           _5 = Lt(_3, _4);                 // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
-          assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
+          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17
       }
   
       bb1: {
@@ -44,7 +44,7 @@
 -         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
 +         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
           _9 = Lt(_7, _8);                 // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
-          assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
+          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17
       }
   
       bb2: {
diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
index c8c1579..bbce9c28 100644
--- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
@@ -33,21 +33,21 @@
 +                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
-          _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
+          _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
                                            // mir::Constant
                                            // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42
                                            // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:45
-      }
-  
-      bb2: {
+      bb1: {
 -         StorageDead(_5);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44
 -         StorageDead(_3);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:43: 9:44
           return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:45
       }
+  
+      bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/const-promotion-extern-static.rs:9:1: 9:45
+      }
 - }
 - 
 - alloc0 (static: Y, size: 4, align: 4) {
diff --git "a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted\1330\135.ConstProp.after.mir" "b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted\1330\135.ConstProp.after.mir"
index d9c6b4f..88d583b 100644
--- "a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted\1330\135.ConstProp.after.mir"
+++ "b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted\1330\135.ConstProp.after.mir"
@@ -4,19 +4,17 @@
     let mut _0: &[&i32; 1];              // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
     let mut _1: [&i32; 1];               // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
     let mut _2: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
-    let mut _3: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
-    scope 1 {
-    }
+    let mut _3: *const i32;              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 
     bb0: {
-        _3 = const {alloc2: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+        _3 = const {alloc2: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
                                          // ty::Const
-                                         // + ty: &i32
+                                         // + ty: *const i32
                                          // + val: Value(Scalar(alloc2))
                                          // mir::Constant
                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
-                                         // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
-        _2 = _3;                         // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
+                                         // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
+        _2 = &(*_3);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
         _1 = [move _2];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
         _0 = &_1;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
         return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index ddf79fc..82277b2 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -7,7 +7,7 @@
       let mut _2: &[&i32; 1];              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
       let _3: [&i32; 1];                   // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
       let mut _4: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
-      let _5: &i32;                        // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+      let _5: *const i32;                  // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 +     let mut _6: &[&i32; 1];              // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
       scope 1 {
       }
@@ -18,16 +18,16 @@
 -         StorageLive(_3);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         StorageLive(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
 -         StorageLive(_5);                 // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
--         _5 = const {alloc2: &i32};       // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
+-         _5 = const {alloc2: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 +         _6 = const FOO::promoted[0];     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
                                            // ty::Const
--                                          // + ty: &i32
+-                                          // + ty: *const i32
 -                                          // + val: Value(Scalar(alloc2))
 +                                          // + ty: &[&i32; 1]
 +                                          // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
--                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
+-                                          // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) }
 -         _4 = &(*_5);                     // scope 1 at $DIR/const-promotion-extern-static.rs:13:41: 13:43
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
@@ -35,21 +35,21 @@
 +                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
-          _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
+          _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
                                            // mir::Constant
                                            // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53
                                            // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:56
-      }
-  
-      bb2: {
+      bb1: {
 -         StorageDead(_5);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55
 -         StorageDead(_3);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:54: 13:55
           return;                          // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:56
       }
+  
+      bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/const-promotion-extern-static.rs:13:1: 13:56
+      }
   }
 - 
 - alloc2 (extern static: X)
diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
index 1ccda1c..4664934 100644
--- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff
@@ -20,9 +20,9 @@
           _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:5:31: 5:32
           _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:5:18: 5:33
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/array_index.rs:5:18: 5:33
--         assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
 +         _5 = const true;                 // scope 0 at $DIR/array_index.rs:5:18: 5:33
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
index 1ccda1c..4664934 100644
--- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff
@@ -20,9 +20,9 @@
           _3 = const 2_usize;              // scope 0 at $DIR/array_index.rs:5:31: 5:32
           _4 = const 4_usize;              // scope 0 at $DIR/array_index.rs:5:18: 5:33
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/array_index.rs:5:18: 5:33
--         assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
 +         _5 = const true;                 // scope 0 at $DIR/array_index.rs:5:18: 5:33
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
index 30ff6ec..ba081f9 100644
--- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff
@@ -24,21 +24,21 @@
           StorageLive(_3);                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
 -         _3 = _1;                         // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
 -         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
--         assert(!move _4, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-         assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
-+         assert(!const true, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++         assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
       }
   
       bb1: {
 -         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 -         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
--         assert(!move _7, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+-         assert(!move _7, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +         _5 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
-+         assert(!const false, "attempt to compute `{} / {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++         assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
       }
   
       bb2: {
diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
index 6e6ce0a..a843cac 100644
--- a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
@@ -24,21 +24,21 @@
           StorageLive(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
 -         _3 = _1;                         // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
 -         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
--         assert(!move _4, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-         assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
-+         assert(!const true, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
       }
   
       bb1: {
 -         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 -         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
--         assert(!move _7, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+-         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +         _5 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
-+         assert(!const false, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
       }
   
       bb2: {
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
index 5f81cb6..8c10b35 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
@@ -42,9 +42,9 @@
           _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
           _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
 -         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
 +         _8 = Lt(const 3_usize, _7);      // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
index 5f81cb6..8c10b35 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
@@ -42,9 +42,9 @@
           _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
           _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
 -         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
 +         _8 = Lt(const 3_usize, _7);      // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
index 51255d5a..1412162 100644
--- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
@@ -23,18 +23,18 @@
           _2 = (*_3);                      // scope 0 at $DIR/boxes.rs:12:13: 12:22
           _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/boxes.rs:12:13: 12:26
           StorageDead(_2);                 // scope 0 at $DIR/boxes.rs:12:25: 12:26
-          drop(_3) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/boxes.rs:12:26: 12:27
+          drop(_3) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/boxes.rs:12:26: 12:27
       }
   
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/boxes.rs:11:1: 13:2
-      }
-  
-      bb2: {
+      bb1: {
           StorageDead(_3);                 // scope 0 at $DIR/boxes.rs:12:26: 12:27
           _0 = const ();                   // scope 0 at $DIR/boxes.rs:11:11: 13:2
           StorageDead(_1);                 // scope 0 at $DIR/boxes.rs:13:1: 13:2
           return;                          // scope 0 at $DIR/boxes.rs:13:2: 13:2
       }
+  
+      bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/boxes.rs:11:1: 13:2
+      }
   }
   
diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
index 125d150..f01676b 100644
--- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff
@@ -12,7 +12,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/checked_add.rs:5:9: 5:10
 -         _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23
--         assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
 +         _2 = const (2_u32, false);       // scope 0 at $DIR/checked_add.rs:5:18: 5:23
 +                                          // ty::Const
 +                                          // + ty: (u32, bool)
@@ -20,7 +20,7 @@
 +                                          // mir::Constant
 +                                          // + span: $DIR/checked_add.rs:5:18: 5:23
 +                                          // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
index e37d0a3..8c7b358 100644
--- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff
@@ -15,7 +15,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/indirect.rs:5:13: 5:25
 -         _2 = const 2_u32 as u8 (Misc);   // scope 0 at $DIR/indirect.rs:5:13: 5:25
 -         _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29
--         assert(!move (_3.1: bool), "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+-         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
 +         _2 = const 2_u8;                 // scope 0 at $DIR/indirect.rs:5:13: 5:25
 +         _3 = const (3_u8, false);        // scope 0 at $DIR/indirect.rs:5:13: 5:29
 +                                          // ty::Const
@@ -24,7 +24,7 @@
 +                                          // mir::Constant
 +                                          // + span: $DIR/indirect.rs:5:13: 5:29
 +                                          // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
index b1a9e1c..fa79082 100644
--- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
@@ -20,9 +20,9 @@
           _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
           _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
--         assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
 +         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
index b1a9e1c..fa79082 100644
--- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
@@ -20,9 +20,9 @@
           _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
           _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
--         assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
 +         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
index 2c8e7ad..53ffc01 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
@@ -25,7 +25,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
 -         _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
--         assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +         _2 = const (4_i32, false);       // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // ty::Const
 +                                          // + ty: (i32, bool)
@@ -33,7 +33,7 @@
 +                                          // mir::Constant
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
       }
   
       bb1: {
@@ -46,9 +46,9 @@
           _5 = const 3_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
           _6 = const 6_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
 -         _7 = Lt(_5, _6);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
--         assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
 +         _7 = const true;                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
       }
   
       bb2: {
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
index 2c8e7ad..53ffc01 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
@@ -25,7 +25,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10
 -         _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
--         assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +         _2 = const (4_i32, false);       // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // ty::Const
 +                                          // + ty: (i32, bool)
@@ -33,7 +33,7 @@
 +                                          // mir::Constant
 +                                          // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18
 +                                          // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18
       }
   
       bb1: {
@@ -46,9 +46,9 @@
           _5 = const 3_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33
           _6 = const 6_usize;              // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
 -         _7 = Lt(_5, _6);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
--         assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
 +         _7 = const true;                 // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
       }
   
       bb2: {
diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
index feef65f..4fd1b8b 100644
--- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
@@ -19,7 +19,7 @@
                                            // + span: $DIR/ref_deref.rs:5:6: 5:10
                                            // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
--         _1 = (*_4);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+-         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 +         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
index 7ec0751..812c7c97 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
@@ -19,7 +19,7 @@
                                            // + span: $DIR/ref_deref_project.rs:5:6: 5:17
                                            // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
-          _1 = ((*_4).1: i32);             // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
+          _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
           StorageDead(_1);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
           _0 = const ();                   // scope 0 at $DIR/ref_deref_project.rs:4:11: 6:2
diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
index f14004f..98f409f 100644
--- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
@@ -22,9 +22,9 @@
           _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:6:26: 6:27
           _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:6:18: 6:28
 -         _6 = Lt(_4, _5);                 // scope 0 at $DIR/repeat.rs:6:18: 6:28
--         assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
 +         _6 = const true;                 // scope 0 at $DIR/repeat.rs:6:18: 6:28
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
index f14004f..98f409f 100644
--- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
@@ -22,9 +22,9 @@
           _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:6:26: 6:27
           _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:6:18: 6:28
 -         _6 = Lt(_4, _5);                 // scope 0 at $DIR/repeat.rs:6:18: 6:28
--         assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
 +         _6 = const true;                 // scope 0 at $DIR/repeat.rs:6:18: 6:28
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff
index d61a04d..fc8a543 100644
--- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff
@@ -7,7 +7,7 @@
   
       bb0: {
 -         _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10
--         assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
+-         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
 +         _1 = const (4_u32, false);       // scope 0 at $DIR/return_place.rs:6:5: 6:10
 +                                          // ty::Const
 +                                          // + ty: (u32, bool)
@@ -15,7 +15,7 @@
 +                                          // mir::Constant
 +                                          // + span: $DIR/return_place.rs:6:5: 6:10
 +                                          // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
index f15dcf2..240cc8e 100644
--- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
@@ -33,10 +33,10 @@
           _6 = const 1_usize;              // scope 0 at $DIR/slice_len.rs:5:31: 5:32
 -         _7 = Len((*_2));                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 -         _8 = Lt(_6, _7);                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
--         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
index f15dcf2..240cc8e 100644
--- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
@@ -33,10 +33,10 @@
           _6 = const 1_usize;              // scope 0 at $DIR/slice_len.rs:5:31: 5:32
 -         _7 = Len((*_2));                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 -         _8 = Lt(_6, _7);                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
--         assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +         _7 = const 3_usize;              // scope 0 at $DIR/slice_len.rs:5:5: 5:33
 +         _8 = const true;                 // scope 0 at $DIR/slice_len.rs:5:5: 5:33
-+         assert(const true, "index out of bounds: the len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
       }
   
       bb1: {
diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs
deleted file mode 100644
index ee460a4..0000000
--- a/src/test/mir-opt/copy_propagation.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// EMIT_MIR copy_propagation.test.CopyPropagation.diff
-
-fn test(x: u32) -> u32 {
-    let y = x;
-    y
-}
-
-fn main() {
-    // Make sure the function actually gets instantiated.
-    test(0);
-}
diff --git a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff
deleted file mode 100644
index 1f3e559..0000000
--- a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff
+++ /dev/null
@@ -1,20 +0,0 @@
-- // MIR for `test` before CopyPropagation
-+ // MIR for `test` after CopyPropagation
-  
-  fn test(_1: u32) -> u32 {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation.rs:3:9: 3:10
-      let mut _0: u32;                     // return place in scope 0 at $DIR/copy_propagation.rs:3:20: 3:23
-      let _2: u32;                         // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10
-      scope 1 {
-          debug y => _0;                   // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10
-      }
-  
-      bb0: {
-          nop;                             // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10
-          _0 = _1;                         // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14
-          nop;                             // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6
-          nop;                             // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2
-          return;                          // scope 0 at $DIR/copy_propagation.rs:6:2: 6:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff
deleted file mode 100644
index 8aab2299d..0000000
--- a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `arg_src` before CopyPropagation
-+ // MIR for `arg_src` after CopyPropagation
-  
-  fn arg_src(_1: i32) -> i32 {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:27:12: 27:17
-      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30
-      let _2: i32;                         // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
-      scope 1 {
-          debug y => _0;                   // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10
-      }
-  
-      bb0: {
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
-          _0 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
-          _1 = const 123_i32;              // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
-          nop;                             // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff
deleted file mode 100644
index fb793e5..0000000
--- a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff
+++ /dev/null
@@ -1,28 +0,0 @@
-- // MIR for `bar` before CopyPropagation
-+ // MIR for `bar` after CopyPropagation
-  
-  fn bar(_1: u8) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:15:8: 15:13
-      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:15:19: 15:19
-      let _2: u8;                          // in scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
-      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
-          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
-          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
-          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
-                                           // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10
-                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:12: 16:13
-          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:13: 16:14
-          _1 = const 5_u8;                 // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10
-          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:18:2: 18:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff
deleted file mode 100644
index 1ea51fe..0000000
--- a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff
+++ /dev/null
@@ -1,18 +0,0 @@
-- // MIR for `baz` before CopyPropagation
-+ // MIR for `baz` after CopyPropagation
-  
-  fn baz(_1: i32) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:21:8: 21:13
-      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:21:20: 21:20
-      let mut _2: i32;                     // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
-  
-      bb0: {
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
-          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff
deleted file mode 100644
index 48ab37a..0000000
--- a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff
+++ /dev/null
@@ -1,28 +0,0 @@
-- // MIR for `foo` before CopyPropagation
-+ // MIR for `foo` after CopyPropagation
-  
-  fn foo(_1: u8) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:9:8: 9:13
-      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:9:19: 9:19
-      let mut _2: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
-      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
-  
-      bb0: {
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
-          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
-          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
-          _1 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
-                                           // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
-                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
-          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/copy_propagation_arg.rs
deleted file mode 100644
index 3a00fc5..0000000
--- a/src/test/mir-opt/copy_propagation_arg.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Check that CopyPropagation does not propagate an assignment to a function argument
-// (doing so can break usages of the original argument value)
-
-fn dummy(x: u8) -> u8 {
-    x
-}
-
-// EMIT_MIR copy_propagation_arg.foo.CopyPropagation.diff
-fn foo(mut x: u8) {
-    // calling `dummy` to make an use of `x` that copyprop cannot eliminate
-    x = dummy(x); // this will assign a local to `x`
-}
-
-// EMIT_MIR copy_propagation_arg.bar.CopyPropagation.diff
-fn bar(mut x: u8) {
-    dummy(x);
-    x = 5;
-}
-
-// EMIT_MIR copy_propagation_arg.baz.CopyPropagation.diff
-fn baz(mut x: i32) {
-    // self-assignment to a function argument should be eliminated
-    x = x;
-}
-
-// EMIT_MIR copy_propagation_arg.arg_src.CopyPropagation.diff
-fn arg_src(mut x: i32) -> i32 {
-    let y = x;
-    x = 123; // Don't propagate this assignment to `y`
-    y
-}
-
-fn main() {
-    // Make sure the function actually gets instantiated.
-    foo(0);
-    bar(0);
-    baz(0);
-    arg_src(0);
-}
diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff
new file mode 100644
index 0000000..a5d80e7
--- /dev/null
+++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff
@@ -0,0 +1,26 @@
+- // MIR for `arg_src` before DestinationPropagation
++ // MIR for `arg_src` after DestinationPropagation
+  
+  fn arg_src(_1: i32) -> i32 {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:27:12: 27:17
+      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30
+      let _2: i32;                         // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
+      scope 1 {
+-         debug y => _2;                   // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10
++         debug y => _0;                   // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
+-         _2 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
++         _0 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
+          _1 = const 123_i32;              // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
+-         _0 = _2;                         // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
+-         StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
++         nop;                             // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
new file mode 100644
index 0000000..dce8800
--- /dev/null
+++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
@@ -0,0 +1,28 @@
+- // MIR for `bar` before DestinationPropagation
++ // MIR for `bar` after DestinationPropagation
+  
+  fn bar(_1: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:15:8: 15:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:15:19: 15:19
+      let _2: u8;                          // in scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
+          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
+                                           // mir::Constant
+                                           // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:12: 16:13
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:13: 16:14
+          _1 = const 5_u8;                 // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:18:2: 18:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff
new file mode 100644
index 0000000..2f8c76e
--- /dev/null
+++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff
@@ -0,0 +1,22 @@
+- // MIR for `baz` before DestinationPropagation
++ // MIR for `baz` after DestinationPropagation
+  
+  fn baz(_1: i32) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:21:8: 21:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:21:20: 21:20
+      let mut _2: i32;                     // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+-         _2 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+-         _1 = move _2;                    // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10
+-         StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
new file mode 100644
index 0000000..2dea530
--- /dev/null
+++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
@@ -0,0 +1,32 @@
+- // MIR for `foo` before DestinationPropagation
++ // MIR for `foo` after DestinationPropagation
+  
+  fn foo(_1: u8) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:9:8: 9:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:9:19: 9:19
+      let mut _2: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
+-         _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
++         _1 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
+                                           // mir::Constant
+                                           // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
+-         _1 = move _2;                    // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17
+-         StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17
++         nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.rs b/src/test/mir-opt/dest-prop/copy_propagation_arg.rs
new file mode 100644
index 0000000..b5188a8
--- /dev/null
+++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.rs
@@ -0,0 +1,39 @@
+// Check that DestinationPropagation does not propagate an assignment to a function argument
+// (doing so can break usages of the original argument value)
+
+fn dummy(x: u8) -> u8 {
+    x
+}
+
+// EMIT_MIR copy_propagation_arg.foo.DestinationPropagation.diff
+fn foo(mut x: u8) {
+    // calling `dummy` to make an use of `x` that copyprop cannot eliminate
+    x = dummy(x); // this will assign a local to `x`
+}
+
+// EMIT_MIR copy_propagation_arg.bar.DestinationPropagation.diff
+fn bar(mut x: u8) {
+    dummy(x);
+    x = 5;
+}
+
+// EMIT_MIR copy_propagation_arg.baz.DestinationPropagation.diff
+fn baz(mut x: i32) {
+    // self-assignment to a function argument should be eliminated
+    x = x;
+}
+
+// EMIT_MIR copy_propagation_arg.arg_src.DestinationPropagation.diff
+fn arg_src(mut x: i32) -> i32 {
+    let y = x;
+    x = 123; // Don't propagate this assignment to `y`
+    y
+}
+
+fn main() {
+    // Make sure the function actually gets instantiated.
+    foo(0);
+    bar(0);
+    baz(0);
+    arg_src(0);
+}
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs
index 5922e73..b822c58 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.rs
+++ b/src/test/mir-opt/early_otherwise_branch_68867.rs
@@ -1,5 +1,5 @@
 // ignore-tidy-linelength
-// compile-flags: -Z mir-opt-level=3
+// compile-flags: -Z mir-opt-level=3 -Zunsound-mir-opts
 
 // example from #68867
 type CSSFloat = f32;
@@ -12,7 +12,7 @@
 }
 
 // EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
-// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-after-copy-prop.after
+// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-final.after
 #[no_mangle]
 pub extern "C" fn try_sum(
     x: &ViewportPercentageLength,
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff
deleted file mode 100644
index fbc46c9..0000000
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff
+++ /dev/null
@@ -1,310 +0,0 @@
-- // MIR for `try_sum` before EarlyOtherwiseBranch
-+ // MIR for `try_sum` after SimplifyBranches-after-copy-prop
-  
-  fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result<ViewportPercentageLength, ()> {
-      debug x => _1;                       // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6
-      debug other => _2;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10
-      let mut _0: std::result::Result<ViewportPercentageLength, ()>; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42
-      let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-      let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
-      let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
-      let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
-      let mut _7: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
-      let mut _8: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30
-      let mut _9: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
-      let mut _10: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34
-      let mut _11: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-      let _12: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-      let _13: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-      let mut _14: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-      let mut _15: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-      let mut _16: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-      let _17: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
-      let _18: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
-      let mut _19: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
-      let mut _20: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
-      let mut _21: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
-      let _22: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-      let _23: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-      let mut _24: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-      let mut _25: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-      let mut _26: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-      let _27: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
-      let _28: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
-      let mut _29: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
-      let mut _30: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
-      let mut _31: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
-      let mut _32: !;                      // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28
-      let mut _33: ();                     // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27
-+     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
-+     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
-      scope 1 {
--         debug one => _12;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
--         debug other => _13;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+         debug one => _15;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+         debug other => _16;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-      }
-      scope 2 {
--         debug one => _17;                // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
--         debug other => _18;              // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
-+         debug one => _20;                // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
-+         debug other => _21;              // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
-      }
-      scope 3 {
--         debug one => _22;                // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
--         debug other => _23;              // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+         debug one => _25;                // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+         debug other => _26;              // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-      }
-      scope 4 {
--         debug one => _27;                // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
--         debug other => _28;              // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
-+         debug one => _30;                // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
-+         debug other => _31;              // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
-      }
-  
-      bb0: {
--         StorageLive(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
--         StorageLive(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
--         StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
--         _5 = _1;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
--         StorageLive(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
--         _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
--         (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
--         (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
--         StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24
--         StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
-+         (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
-+         (_4.1: &ViewportPercentageLength) = move _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24
-          _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
--         switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-+         StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-+         _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-+         StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-+         _35 = Ne(_34, _11);              // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-+         StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-+         switchInt(move _35) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-      }
-  
-      bb1: {
--         _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
--         switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
--     }
-- 
--     bb2: {
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27
-          StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27
-          ((_0 as Err).0: ()) = const ();  // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28
-          discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28
-          StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28
--         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
--         StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28
-      }
-  
-+     bb2: {
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+         _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+         _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
-+         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+     }
-+ 
-      bb3: {
--         _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30
--         switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
-+         _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
-+         _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
-+         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-      }
-  
-      bb4: {
--         _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
--         switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+         _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+         _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
-+         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-      }
-  
-      bb5: {
--         _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34
--         switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
-+         _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
-+         _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
-+         ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
-+         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
-+         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-      }
-  
-      bb6: {
--         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
--         _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
--         StorageLive(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
--         _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
--         StorageLive(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
--         StorageLive(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
--         _15 = _12;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
--         StorageLive(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
--         _16 = _13;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
--         _14 = Add(move _15, move _16);   // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
--         StorageDead(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
--         StorageDead(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
--         ((_3 as Vw).0: f32) = move _14;  // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
--         discriminant(_3) = 0;            // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
--         StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
--         StorageDead(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
--         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+         return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
-      }
-  
-      bb7: {
--         StorageLive(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
--         _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
--         StorageLive(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
--         _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
--         StorageLive(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
--         StorageLive(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
--         _20 = _17;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
--         StorageLive(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
--         _21 = _18;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
--         _19 = Add(move _20, move _21);   // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
--         StorageDead(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
--         StorageDead(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
--         ((_3 as Vh).0: f32) = move _19;  // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
--         discriminant(_3) = 1;            // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
--         StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
--         StorageDead(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
--         StorageDead(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
-+         discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
-+         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
-      }
-  
-      bb8: {
--         StorageLive(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
--         _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
--         StorageLive(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
--         _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
--         StorageLive(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
--         StorageLive(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
--         _25 = _22;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
--         StorageLive(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
--         _26 = _23;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
--         _24 = Add(move _25, move _26);   // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
--         StorageDead(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
--         StorageDead(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
--         ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
--         discriminant(_3) = 2;            // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
--         StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
--         StorageDead(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
--         StorageDead(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
--     }
-- 
--     bb9: {
--         StorageLive(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
--         _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
--         StorageLive(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
--         _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
--         StorageLive(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
--         StorageLive(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
--         _30 = _27;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
--         StorageLive(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
--         _31 = _28;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
--         _29 = Add(move _30, move _31);   // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
--         StorageDead(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
--         StorageDead(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
--         ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
--         discriminant(_3) = 3;            // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
--         StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
--         StorageDead(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
--         StorageDead(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
--     }
-- 
--     bb10: {
--         return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
--     }
-- 
--     bb11: {
--         ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
--         discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
--         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
--         StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
-+         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
-      }
-  }
-  
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff
new file mode 100644
index 0000000..f51a08e
--- /dev/null
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff
@@ -0,0 +1,300 @@
+- // MIR for `try_sum` before EarlyOtherwiseBranch
++ // MIR for `try_sum` after SimplifyBranches-final
+  
+  fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result<ViewportPercentageLength, ()> {
+      debug x => _1;                       // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6
+      debug other => _2;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10
+      let mut _0: std::result::Result<ViewportPercentageLength, ()>; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42
+      let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+      let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
+      let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
+      let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
+      let mut _7: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
+      let mut _8: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30
+      let mut _9: isize;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
+      let mut _10: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34
+      let mut _11: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
+      let _12: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+      let _13: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+      let mut _14: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
+      let mut _15: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
+      let mut _16: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
+      let _17: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
+      let _18: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
+      let mut _19: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
+      let mut _20: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
+      let mut _21: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
+      let _22: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+      let _23: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+      let mut _24: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
+      let mut _25: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
+      let mut _26: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
+      let _27: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
+      let _28: f32;                        // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
+      let mut _29: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
+      let mut _30: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
+      let mut _31: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
+      let mut _32: !;                      // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28
+      let mut _33: ();                     // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27
++     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
++     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
+      scope 1 {
+-         debug one => _12;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+-         debug other => _13;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++         debug one => _15;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++         debug other => _16;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+      }
+      scope 2 {
+-         debug one => _17;                // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
+-         debug other => _18;              // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
++         debug one => _20;                // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
++         debug other => _21;              // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
+      }
+      scope 3 {
+-         debug one => _22;                // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+-         debug other => _23;              // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++         debug one => _25;                // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++         debug other => _26;              // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+      }
+      scope 4 {
+-         debug one => _27;                // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
+-         debug other => _28;              // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
++         debug one => _30;                // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
++         debug other => _31;              // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
+      }
+  
+      bb0: {
+-         StorageLive(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-         StorageLive(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
+-         StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
+-         _5 = _1;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
++         (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16
+          StorageLive(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
+          _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23
+-         (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
+          (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24
+          StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24
+-         StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24
+          _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
+-         switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
++         StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
++         _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
++         StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
++         _35 = Ne(_34, _11);              // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
++         StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
++         switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
+      }
+  
+      bb1: {
+-         _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
+-         switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
+-     }
+- 
+-     bb2: {
++         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27
+          StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27
+          ((_0 as Err).0: ()) = const ();  // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28
+          discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28
+          StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28
+-         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
+-         StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
+          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
+      }
+  
++     bb2: {
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++         _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++         _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
++         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
++     }
++ 
+      bb3: {
+-         _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30
+-         switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
++         _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
++         _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
++         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+      }
+  
+      bb4: {
+-         _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
+-         switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++         _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++         _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
++         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+      }
+  
+      bb5: {
+-         _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34
+-         switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
++         _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
++         _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
++         ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
++         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
++         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+      }
+  
+      bb6: {
+-         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+-         _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17
+-         StorageLive(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+-         _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29
+-         StorageLive(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
+-         StorageLive(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
+-         _15 = _12;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41
+-         StorageLive(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
+-         _16 = _13;                       // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49
+-         _14 = Add(move _15, move _16);   // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
+-         StorageDead(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
+-         StorageDead(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
+-         ((_3 as Vw).0: f32) = move _14;  // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
+-         discriminant(_3) = 0;            // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
+-         StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+-         StorageDead(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+-         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
++         discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
++         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
++         return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
+      }
+  
+      bb7: {
+-         StorageLive(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
+-         _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17
+-         StorageLive(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
+-         _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29
+-         StorageLive(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
+-         StorageLive(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
+-         _20 = _17;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41
+-         StorageLive(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
+-         _21 = _18;                       // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49
+-         _19 = Add(move _20, move _21);   // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49
+-         StorageDead(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
+-         StorageDead(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49
+-         ((_3 as Vh).0: f32) = move _19;  // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
+-         discriminant(_3) = 1;            // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50
+-         StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
+-         StorageDead(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
+-         StorageDead(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-     }
+- 
+-     bb8: {
+-         StorageLive(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+-         _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19
+-         StorageLive(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+-         _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33
+-         StorageLive(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
+-         StorageLive(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
+-         _25 = _22;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47
+-         StorageLive(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
+-         _26 = _23;                       // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
+-         _24 = Add(move _25, move _26);   // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
+-         StorageDead(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
+-         StorageDead(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
+-         ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
+-         discriminant(_3) = 2;            // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
+-         StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+-         StorageDead(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+-         StorageDead(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-     }
+- 
+-     bb9: {
+-         StorageLive(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
+-         _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19
+-         StorageLive(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
+-         _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33
+-         StorageLive(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
+-         StorageLive(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
+-         _30 = _27;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47
+-         StorageLive(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
+-         _31 = _28;                       // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55
+-         _29 = Add(move _30, move _31);   // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55
+-         StorageDead(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
+-         StorageDead(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55
+-         ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
+-         discriminant(_3) = 3;            // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56
+-         StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
+-         StorageDead(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
+-         StorageDead(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-     }
+- 
+-     bb10: {
+-         ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
+-         discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
+-         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
+-         StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
+-         return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
++         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
++         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
+      }
+  }
+  
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
index 54e4b08..05ef672 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
@@ -73,7 +73,7 @@
 +         StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
 +         _35 = Ne(_34, _11);              // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
 +         StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
-+         switchInt(move _35) -> [false: bb8, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
++         switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18
       }
   
       bb1: {
@@ -89,8 +89,7 @@
           StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28
+          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
       }
   
 -     bb3: {
@@ -127,8 +126,8 @@
           StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
           StorageDead(_13);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
           StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
       }
   
 -     bb7: {
@@ -150,8 +149,8 @@
           StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
           StorageDead(_18);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
           StorageDead(_17);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
       }
   
 -     bb8: {
@@ -173,8 +172,8 @@
           StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
           StorageDead(_23);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
           StorageDead(_22);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
       }
   
 -     bb9: {
@@ -196,26 +195,20 @@
           StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
           StorageDead(_28);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
           StorageDead(_27);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56
--         goto -> bb11;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
-+         goto -> bb7;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
+-         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
++         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6
       }
   
 -     bb10: {
 +     bb6: {
-          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
-      }
-  
--     bb11: {
-+     bb7: {
           ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
           discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7
           StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2
--         goto -> bb10;                    // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
-+         goto -> bb6;                     // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
+          return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2
 +     }
 + 
-+     bb8: {
++     bb7: {
 +         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
 +         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30
       }
diff --git "a/src/test/mir-opt/generator_drop_cleanup.main-\173closure\0430\175.generator_drop.0.mir" "b/src/test/mir-opt/generator_drop_cleanup.main-\173closure\0430\175.generator_drop.0.mir"
index 31f8546..8e8ab08 100644
--- "a/src/test/mir-opt/generator_drop_cleanup.main-\173closure\0430\175.generator_drop.0.mir"
+++ "b/src/test/mir-opt/generator_drop_cleanup.main-\173closure\0430\175.generator_drop.0.mir"
@@ -34,60 +34,56 @@
 
     bb0: {
         _9 = discriminant((*_1));        // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-        switchInt(move _9) -> [0_u32: bb7, 3_u32: bb11, otherwise: bb12]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        switchInt(move _9) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+    bb1: {
+        StorageDead(_5);                 // scope 1 at $DIR/generator-drop-cleanup.rs:12:13: 12:14
+        StorageDead(_4);                 // scope 1 at $DIR/generator-drop-cleanup.rs:12:14: 12:15
+        drop((((*_1) as variant#3).0: std::string::String)) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
     }
 
-    bb2 (cleanup): {
+    bb2: {
         nop;                             // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
         goto -> bb8;                     // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
     }
 
     bb3: {
-        StorageDead(_5);                 // scope 1 at $DIR/generator-drop-cleanup.rs:12:13: 12:14
-        StorageDead(_4);                 // scope 1 at $DIR/generator-drop-cleanup.rs:12:14: 12:15
-        drop((((*_1) as variant#3).0: std::string::String)) -> [return: bb4, unwind: bb2]; // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
-    }
-
-    bb4: {
-        nop;                             // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
-        goto -> bb9;                     // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
-    }
-
-    bb5: {
         return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 
+    bb4 (cleanup): {
+        resume;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+    }
+
+    bb5 (cleanup): {
+        nop;                             // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
+        goto -> bb4;                     // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
+    }
+
     bb6: {
         return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 
     bb7: {
-        goto -> bb10;                    // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        goto -> bb9;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 
-    bb8 (cleanup): {
-        goto -> bb1;                     // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
+    bb8: {
+        goto -> bb3;                     // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
     }
 
     bb9: {
-        goto -> bb5;                     // scope 0 at $DIR/generator-drop-cleanup.rs:13:5: 13:6
-    }
-
-    bb10: {
         goto -> bb6;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 
-    bb11: {
+    bb10: {
         StorageLive(_4);                 // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
         StorageLive(_5);                 // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-        goto -> bb3;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        goto -> bb1;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 
-    bb12: {
+    bb11: {
         return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     }
 }
diff --git "a/src/test/mir-opt/generator_storage_dead_unwind.main-\173closure\0430\175.StateTransform.before.mir" "b/src/test/mir-opt/generator_storage_dead_unwind.main-\173closure\0430\175.StateTransform.before.mir"
index b76e412..42b95b5 100644
--- "a/src/test/mir-opt/generator_storage_dead_unwind.main-\173closure\0430\175.StateTransform.before.mir"
+++ "b/src/test/mir-opt/generator_storage_dead_unwind.main-\173closure\0430\175.StateTransform.before.mir"
@@ -26,86 +26,86 @@
         (_4.0: i32) = const 6_i32;       // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
         StorageLive(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
         StorageLive(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
-        _5 = yield(move _6) -> [resume: bb2, drop: bb4]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
+        _5 = yield(move _6) -> [resume: bb1, drop: bb5]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14
         StorageDead(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15
         StorageLive(_7);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
         StorageLive(_8);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15
         _8 = move _3;                    // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:14: 26:15
-        _7 = take::<Foo>(move _8) -> [return: bb7, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
+        _7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
                                          // mir::Constant
                                          // + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13
                                          // + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb3 (cleanup): {
-        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> bb1;                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-    }
-
-    bb4: {
-        StorageDead(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14
-        StorageDead(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15
-        StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_3) -> [return: bb5, unwind: bb3]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-    }
-
-    bb5: {
-        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> [return: bb6, unwind: bb1]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-    }
-
-    bb6: {
-        generator_drop;                  // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6
-    }
-
-    bb7: {
+    bb2: {
         StorageDead(_8);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
         StorageDead(_7);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
         StorageLive(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
         StorageLive(_10);                // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15
         _10 = move _4;                   // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:14: 27:15
-        _9 = take::<Bar>(move _10) -> [return: bb10, unwind: bb11]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
+        _9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
                                          // mir::Constant
                                          // + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13
                                          // + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb8 (cleanup): {
-        StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> bb1;                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-    }
-
-    bb9 (cleanup): {
-        StorageDead(_8);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
-        StorageDead(_7);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
-        goto -> bb8;                     // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
-    }
-
-    bb10: {
+    bb3: {
         StorageDead(_10);                // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16
         StorageDead(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
         _0 = const ();                   // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 28:6
         StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
         StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
-        drop(_1) -> [return: bb12, unwind: bb1]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> [return: bb4, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+    }
+
+    bb4: {
+        return;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:6: 28:6
+    }
+
+    bb5: {
+        StorageDead(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:13: 25:14
+        StorageDead(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:14: 25:15
+        StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_3) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+    }
+
+    bb6: {
+        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+    }
+
+    bb7: {
+        generator_drop;                  // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6
+    }
+
+    bb8 (cleanup): {
+        StorageDead(_10);                // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16
+        StorageDead(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
+        goto -> bb10;                    // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
+    }
+
+    bb9 (cleanup): {
+        StorageDead(_8);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
+        StorageDead(_7);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
+        goto -> bb10;                    // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
+    }
+
+    bb10 (cleanup): {
+        StorageDead(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> bb11;                // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 
     bb11 (cleanup): {
-        StorageDead(_10);                // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16
-        StorageDead(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
-        goto -> bb8;                     // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
+        resume;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6
     }
 
-    bb12: {
-        return;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:6: 28:6
+    bb12 (cleanup): {
+        StorageDead(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
+        drop(_1) -> bb11;                // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:5: 28:6
     }
 }
diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot b/src/test/mir-opt/graphviz.main.mir_map.0.dot
index df4f11f..8d1da7f 100644
--- a/src/test/mir-opt/graphviz.main.mir_map.0.dot
+++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot
@@ -3,8 +3,5 @@
     node [fontname="Courier, monospace"];
     edge [fontname="Courier, monospace"];
     label=<fn main() -&gt; ()<br align="left"/>>;
-    bb0__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = const ()<br/></td></tr><tr><td align="left">goto</td></tr></table>>];
-    bb1__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>>];
-    bb2__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">2</td></tr><tr><td align="left">return</td></tr></table>>];
-    bb0__0_3 -> bb2__0_3 [label=""];
+    bb0__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = const ()<br/></td></tr><tr><td align="left">return</td></tr></table>>];
 }
diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir
deleted file mode 100644
index df4f11f..0000000
--- a/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir
+++ /dev/null
@@ -1,10 +0,0 @@
-digraph Mir_0_3 {
-    graph [fontname="Courier, monospace"];
-    node [fontname="Courier, monospace"];
-    edge [fontname="Courier, monospace"];
-    label=<fn main() -&gt; ()<br align="left"/>>;
-    bb0__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = const ()<br/></td></tr><tr><td align="left">goto</td></tr></table>>];
-    bb1__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>>];
-    bb2__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">2</td></tr><tr><td align="left">return</td></tr></table>>];
-    bb0__0_3 -> bb2__0_3 [label=""];
-}
diff --git a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs
index 218bc35..d76bc33 100644
--- a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs
+++ b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z span_free_formats
+// compile-flags: -Z span_free_formats -Zunsound-mir-opts
 
 // Tests that MIR inliner can handle closure arguments,
 // even when (#45894)
diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
index 756f313..4d62329 100644
--- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
@@ -4,13 +4,15 @@
     let mut _0: bool;                    // return place in scope 0 at $DIR/inline-any-operand.rs:10:13: 10:17
     let _1: fn(i32, i32) -> bool {foo};  // in scope 0 at $DIR/inline-any-operand.rs:11:9: 11:10
     let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:6
-    let mut _3: i32;                     // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13
-    let mut _4: i32;                     // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13
+    let mut _5: i32;                     // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13
+    let mut _6: i32;                     // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13
     scope 1 {
         debug f => _1;                   // in scope 1 at $DIR/inline-any-operand.rs:11:9: 11:10
         scope 2 {
-            debug x => _3;               // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9
-            debug y => _4;               // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17
+            debug x => _5;               // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9
+            debug y => _6;               // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17
+            let mut _3: i32;             // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13
+            let mut _4: i32;             // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13
         }
     }
 
@@ -22,13 +24,19 @@
                                          // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
         StorageLive(_2);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
         _2 = _1;                         // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
-        StorageLive(_3);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
-        _3 = const 1_i32;                // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
-        StorageLive(_4);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
-        _4 = const -1_i32;               // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        StorageLive(_5);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        _5 = const 1_i32;                // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        StorageLive(_6);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        _6 = const -1_i32;               // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        StorageLive(_3);                 // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6
+        _3 = _5;                         // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6
+        StorageLive(_4);                 // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
+        _4 = _6;                         // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
         _0 = Eq(move _3, move _4);       // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11
-        StorageDead(_4);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
-        StorageDead(_3);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        StorageDead(_4);                 // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
+        StorageDead(_3);                 // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
+        StorageDead(_6);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+        StorageDead(_5);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
         StorageDead(_2);                 // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13
         StorageDead(_1);                 // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2
         return;                          // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2
diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index cb222a9..5138b50 100644
--- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -4,10 +4,10 @@
     debug t => _1;                       // in scope 0 at $DIR/inline-closure-captures.rs:10:17: 10:18
     debug q => _2;                       // in scope 0 at $DIR/inline-closure-captures.rs:10:23: 10:24
     let mut _0: (i32, T);                // return place in scope 0 at $DIR/inline-closure-captures.rs:10:34: 10:42
-    let _3: [closure@foo<T>::{closure#0} q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10
+    let _3: [closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10
     let mut _4: &i32;                    // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
     let mut _5: &T;                      // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
-    let mut _6: &[closure@foo<T>::{closure#0} q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6
+    let mut _6: &[closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6
     let mut _7: (i32,);                  // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9
     let mut _8: i32;                     // in scope 0 at $DIR/inline-closure-captures.rs:12:7: 12:8
     let mut _10: i32;                    // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
index 2d52f03..fac2f6b 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
@@ -17,7 +17,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
           StorageLive(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
--         (*_2) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+-         (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL
 +                                          // ty::Const
@@ -27,34 +27,33 @@
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 -                                          // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
+-     }
+- 
+-     bb1: {
 +                                          // + span: $SRC_DIR/alloc/src/vec.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
 +         ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL
-+         _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-+         StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
-+         _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
-+         drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
+          _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+          _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
+-         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
++         drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
       }
   
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
-      }
-  
-      bb2: {
--         _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
--         StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
--         _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
--         drop(_1) -> [return: bb3, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
--     }
-- 
--     bb3: {
+-     bb2: {
++     bb1: {
           StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2
+      }
+  
+-     bb3 (cleanup): {
++     bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
 -     }
 - 
 -     bb4 (cleanup): {
--         _3 = alloc::alloc::box_free::<Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+-         _3 = alloc::alloc::box_free::<Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>) {alloc::alloc::box_free::<std::vec::Vec<u32>>}, val: Value(Scalar(<ZST>)) }
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
index d4e2df6..4535cf2 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
@@ -17,7 +17,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
           StorageLive(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
--         (*_2) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+-         (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL
 +                                          // ty::Const
@@ -27,34 +27,33 @@
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
 -                                          // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
+-     }
+- 
+-     bb1: {
 +                                          // + span: $SRC_DIR/alloc/src/vec.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
 +         ((*_4).1: usize) = const 0_usize; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL
-+         _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-+         StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
-+         _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
-+         drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
+          _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+          _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
+-         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
++         drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
       }
   
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
-      }
-  
-      bb2: {
--         _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
--         StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
--         _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
--         drop(_1) -> [return: bb3, unwind: bb1]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
--     }
-- 
--     bb3: {
+-     bb2: {
++     bb1: {
           StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2
+      }
+  
+-     bb3 (cleanup): {
++     bb2 (cleanup): {
+          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
 -     }
 - 
 -     bb4 (cleanup): {
--         _3 = alloc::alloc::box_free::<Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+-         _3 = alloc::alloc::box_free::<Vec<u32>>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>) {alloc::alloc::box_free::<std::vec::Vec<u32>>}, val: Value(Scalar(<ZST>)) }
diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
index 00e3ef0..0954620 100644
--- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
@@ -7,6 +7,7 @@
     let mut _3: &dyn X;                  // in scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11
     scope 1 {
         debug x => _2;                   // in scope 1 at $DIR/inline-trait-method_2.rs:9:9: 9:10
+        let mut _4: &dyn X;              // in scope 1 at $DIR/inline-trait-method_2.rs:5:5: 5:12
     }
 
     bb0: {
@@ -15,13 +16,16 @@
         _3 = &(*_1);                     // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11
         _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11
         StorageDead(_3);                 // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11
-        _0 = <dyn X as X>::y(move _2) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
+        StorageLive(_4);                 // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6
+        _4 = _2;                         // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6
+        _0 = <dyn X as X>::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
                                          // mir::Constant
                                          // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8
                                          // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {<dyn X as X>::y}, val: Value(Scalar(<ZST>)) }
     }
 
     bb1: {
+        StorageDead(_4);                 // scope 1 at $DIR/inline-trait-method_2.rs:10:9: 10:10
         StorageDead(_2);                 // scope 0 at $DIR/inline-trait-method_2.rs:5:11: 5:12
         return;                          // scope 0 at $DIR/inline-trait-method_2.rs:6:2: 6:2
     }
diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs
index 3be8c2f..78361c3 100644
--- a/src/test/mir-opt/inst_combine_deref.rs
+++ b/src/test/mir-opt/inst_combine_deref.rs
@@ -1,4 +1,4 @@
-// compile-flags: -O
+// compile-flags: -O -Zunsound-mir-opts
 // EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff
 fn simple_opt() -> u64 {
     let x = 5;
diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
index 5b25726..5048359 100644
--- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
@@ -6,7 +6,7 @@
   
       bb0: {
           _0 = const true;                 // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9
-+         Coverage::Counter(0) for /the/src/instrument_coverage.rs:19:18 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:5 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2
           return;                          // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2
       }
   }
diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
index 03affed..598727e 100644
--- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
@@ -8,41 +8,42 @@
       let mut _3: !;                       // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10
   
       bb0: {
-+         Coverage::Counter(0) for /the/src/instrument_coverage.rs:10:11 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
-          falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:12:12 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+          falseUnwind -> [real: bb1, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
       }
   
       bb1: {
           StorageLive(_2);                 // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
-          _2 = bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
+          _2 = bar() -> [return: bb2, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
                                            // mir::Constant
                                            // + span: /the/src/instrument_coverage.rs:12:12: 12:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb2 (cleanup): {
-          resume;                          // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2
+      bb2: {
+          FakeRead(ForMatchedPlace, _2);   // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
+          switchInt(_2) -> [false: bb4, otherwise: bb3]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
       }
   
       bb3: {
-          FakeRead(ForMatchedPlace, _2);   // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
-          switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
++         Coverage::Counter(2) for /the/src/instrument_coverage.rs:13:13 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
+          falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
       }
   
       bb4: {
-          falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
-      }
-  
-      bb5: {
           _1 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6
           goto -> bb0;                     // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
       }
   
-      bb6: {
+      bb5: {
           _0 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6
           return;                          // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
       }
+  
+      bb6 (cleanup): {
+          resume;                          // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2
+      }
   }
   
diff --git a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir
index 6bde4da..0929ba9 100644
--- a/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir
+++ b/src/test/mir-opt/issue_38669.main.SimplifyCfg-initial.after.mir
@@ -15,43 +15,43 @@
         StorageLive(_1);                 // scope 0 at $DIR/issue-38669.rs:5:9: 5:25
         _1 = const false;                // scope 0 at $DIR/issue-38669.rs:5:28: 5:33
         FakeRead(ForLet, _1);            // scope 0 at $DIR/issue-38669.rs:5:9: 5:25
-        goto -> bb2;                     // scope 1 at $DIR/issue-38669.rs:6:5: 11:6
+        goto -> bb1;                     // scope 1 at $DIR/issue-38669.rs:6:5: 11:6
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-38669.rs:4:1: 12:2
+    bb1: {
+        falseUnwind -> [real: bb2, cleanup: bb6]; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6
     }
 
     bb2: {
-        falseUnwind -> [real: bb3, cleanup: bb1]; // scope 1 at $DIR/issue-38669.rs:6:5: 11:6
-    }
-
-    bb3: {
         StorageLive(_3);                 // scope 1 at $DIR/issue-38669.rs:7:9: 9:10
         StorageLive(_4);                 // scope 1 at $DIR/issue-38669.rs:7:12: 7:24
         _4 = _1;                         // scope 1 at $DIR/issue-38669.rs:7:12: 7:24
         FakeRead(ForMatchedPlace, _4);   // scope 1 at $DIR/issue-38669.rs:7:12: 7:24
-        switchInt(_4) -> [false: bb5, otherwise: bb4]; // scope 1 at $DIR/issue-38669.rs:7:9: 9:10
+        switchInt(_4) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/issue-38669.rs:7:9: 9:10
+    }
+
+    bb3: {
+        falseEdge -> [real: bb5, imaginary: bb4]; // scope 1 at $DIR/issue-38669.rs:7:9: 9:10
     }
 
     bb4: {
-        falseEdge -> [real: bb6, imaginary: bb5]; // scope 1 at $DIR/issue-38669.rs:7:9: 9:10
-    }
-
-    bb5: {
         _3 = const ();                   // scope 1 at $DIR/issue-38669.rs:7:9: 9:10
         StorageDead(_4);                 // scope 1 at $DIR/issue-38669.rs:9:9: 9:10
         StorageDead(_3);                 // scope 1 at $DIR/issue-38669.rs:9:9: 9:10
         _1 = const true;                 // scope 1 at $DIR/issue-38669.rs:10:9: 10:28
         _2 = const ();                   // scope 1 at $DIR/issue-38669.rs:6:10: 11:6
-        goto -> bb2;                     // scope 1 at $DIR/issue-38669.rs:6:5: 11:6
+        goto -> bb1;                     // scope 1 at $DIR/issue-38669.rs:6:5: 11:6
     }
 
-    bb6: {
+    bb5: {
         _0 = const ();                   // scope 1 at $DIR/issue-38669.rs:8:13: 8:18
         StorageDead(_4);                 // scope 1 at $DIR/issue-38669.rs:9:9: 9:10
         StorageDead(_3);                 // scope 1 at $DIR/issue-38669.rs:9:9: 9:10
         StorageDead(_1);                 // scope 0 at $DIR/issue-38669.rs:12:1: 12:2
         return;                          // scope 0 at $DIR/issue-38669.rs:12:2: 12:2
     }
+
+    bb6 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-38669.rs:4:1: 12:2
+    }
 }
diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir
index 04dea167..7113c42 100644
--- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir
+++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir
@@ -20,38 +20,22 @@
         StorageLive(_3);                 // scope 0 at $DIR/issue-41110.rs:8:21: 8:27
         StorageLive(_4);                 // scope 0 at $DIR/issue-41110.rs:8:21: 8:22
         _4 = S;                          // scope 0 at $DIR/issue-41110.rs:8:21: 8:22
-        _3 = S::id(move _4) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27
+        _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27
                                          // mir::Constant
                                          // + span: $DIR/issue-41110.rs:8:23: 8:25
                                          // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41110.rs:7:1: 9:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_4);                 // scope 0 at $DIR/issue-41110.rs:8:26: 8:27
         _5 = const false;                // scope 0 at $DIR/issue-41110.rs:8:13: 8:28
-        _1 = S::other(move _2, move _3) -> [return: bb6, unwind: bb5]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28
+        _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28
                                          // mir::Constant
                                          // + span: $DIR/issue-41110.rs:8:15: 8:20
                                          // + literal: Const { ty: fn(S, S) {S::other}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb3 (cleanup): {
-        goto -> bb9;                     // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
-    }
-
-    bb4 (cleanup): {
-        goto -> bb3;                     // scope 0 at $DIR/issue-41110.rs:8:26: 8:27
-    }
-
-    bb5 (cleanup): {
-        goto -> bb3;                     // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
-    }
-
-    bb6: {
+    bb2: {
         StorageDead(_3);                 // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
         _5 = const false;                // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
         StorageDead(_2);                 // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
@@ -60,16 +44,27 @@
         return;                          // scope 0 at $DIR/issue-41110.rs:9:2: 9:2
     }
 
+    bb3 (cleanup): {
+        goto -> bb5;                     // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
+    }
+
+    bb4 (cleanup): {
+        goto -> bb5;                     // scope 0 at $DIR/issue-41110.rs:8:26: 8:27
+    }
+
+    bb5 (cleanup): {
+        goto -> bb8;                     // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
+    }
+
+    bb6 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-41110.rs:7:1: 9:2
+    }
+
     bb7 (cleanup): {
-        drop(_2) -> bb1;                 // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
+        drop(_2) -> bb6;                 // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
     }
 
     bb8 (cleanup): {
-        _5 = const false;                // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
-        goto -> bb7;                     // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
-    }
-
-    bb9 (cleanup): {
-        switchInt(_5) -> [false: bb1, otherwise: bb8]; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
+        switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28
     }
 }
diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir
index c4a2e7a..c4e852c 100644
--- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir
+++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir
@@ -25,17 +25,13 @@
         StorageLive(_3);                 // scope 2 at $DIR/issue-41110.rs:17:5: 17:12
         StorageLive(_4);                 // scope 2 at $DIR/issue-41110.rs:17:10: 17:11
         _4 = move _2;                    // scope 2 at $DIR/issue-41110.rs:17:10: 17:11
-        _3 = std::mem::drop::<S>(move _4) -> [return: bb2, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12
+        _3 = std::mem::drop::<S>(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12
                                          // mir::Constant
                                          // + span: $DIR/issue-41110.rs:17:5: 17:9
                                          // + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41110.rs:14:1: 19:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_4);                 // scope 2 at $DIR/issue-41110.rs:17:11: 17:12
         StorageDead(_3);                 // scope 2 at $DIR/issue-41110.rs:17:12: 17:13
         StorageLive(_5);                 // scope 2 at $DIR/issue-41110.rs:18:9: 18:10
@@ -44,63 +40,62 @@
         goto -> bb12;                    // scope 2 at $DIR/issue-41110.rs:18:5: 18:6
     }
 
-    bb3 (cleanup): {
-        goto -> bb15;                    // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
+    bb2: {
+        goto -> bb3;                     // scope 2 at $DIR/issue-41110.rs:18:9: 18:10
     }
 
-    bb4 (cleanup): {
-        goto -> bb3;                     // scope 1 at $DIR/issue-41110.rs:19:1: 19:2
-    }
-
-    bb5 (cleanup): {
-        goto -> bb4;                     // scope 2 at $DIR/issue-41110.rs:17:11: 17:12
-    }
-
-    bb6: {
-        goto -> bb8;                     // scope 2 at $DIR/issue-41110.rs:18:9: 18:10
-    }
-
-    bb7 (cleanup): {
-        goto -> bb4;                     // scope 2 at $DIR/issue-41110.rs:18:9: 18:10
-    }
-
-    bb8: {
+    bb3: {
         StorageDead(_5);                 // scope 2 at $DIR/issue-41110.rs:18:9: 18:10
         _0 = const ();                   // scope 0 at $DIR/issue-41110.rs:14:15: 19:2
-        drop(_2) -> [return: bb9, unwind: bb3]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2
+        drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2
     }
 
-    bb9: {
+    bb4: {
         StorageDead(_2);                 // scope 1 at $DIR/issue-41110.rs:19:1: 19:2
-        goto -> bb10;                    // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
+        goto -> bb5;                     // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
     }
 
-    bb10: {
+    bb5: {
         _6 = const false;                // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
         StorageDead(_1);                 // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
         return;                          // scope 0 at $DIR/issue-41110.rs:19:2: 19:2
     }
 
-    bb11 (cleanup): {
-        _2 = move _5;                    // scope 2 at $DIR/issue-41110.rs:18:5: 18:6
-        goto -> bb7;                     // scope 2 at $DIR/issue-41110.rs:18:5: 18:6
+    bb6 (cleanup): {
+        goto -> bb8;                     // scope 2 at $DIR/issue-41110.rs:18:9: 18:10
     }
 
-    bb12: {
+    bb7 (cleanup): {
+        goto -> bb8;                     // scope 2 at $DIR/issue-41110.rs:17:11: 17:12
+    }
+
+    bb8 (cleanup): {
+        goto -> bb9;                     // scope 1 at $DIR/issue-41110.rs:19:1: 19:2
+    }
+
+    bb9 (cleanup): {
+        goto -> bb14;                    // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
+    }
+
+    bb10 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-41110.rs:14:1: 19:2
+    }
+
+    bb11 (cleanup): {
         _2 = move _5;                    // scope 2 at $DIR/issue-41110.rs:18:5: 18:6
         goto -> bb6;                     // scope 2 at $DIR/issue-41110.rs:18:5: 18:6
     }
 
+    bb12: {
+        _2 = move _5;                    // scope 2 at $DIR/issue-41110.rs:18:5: 18:6
+        goto -> bb2;                     // scope 2 at $DIR/issue-41110.rs:18:5: 18:6
+    }
+
     bb13 (cleanup): {
-        drop(_1) -> bb1;                 // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
+        drop(_1) -> bb10;                // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
     }
 
     bb14 (cleanup): {
-        _6 = const false;                // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
-        goto -> bb13;                    // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
-    }
-
-    bb15 (cleanup): {
-        switchInt(_6) -> [false: bb1, otherwise: bb14]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
+        switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2
     }
 }
diff --git "a/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.32bit.mir" "b/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.32bit.mir"
index 26d1f94..db9caf8 100644
--- "a/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.32bit.mir"
+++ "b/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.32bit.mir"
@@ -6,15 +6,15 @@
 
     bb0: {
         _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
-        assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
-    }
-
-    bb2: {
+    bb1: {
         _0 = move (_1.0: usize);         // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
         return;                          // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
     }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+    }
 }
diff --git "a/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.64bit.mir" "b/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.64bit.mir"
index 26d1f94..db9caf8 100644
--- "a/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.64bit.mir"
+++ "b/src/test/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.64bit.mir"
@@ -6,15 +6,15 @@
 
     bb0: {
         _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
-        assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
-    }
-
-    bb2: {
+    bb1: {
         _0 = move (_1.0: usize);         // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
         return;                          // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
     }
+
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-41697.rs:18:19: 18:22
+    }
 }
diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir
index 84ba4d7..d7b4e07 100644
--- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir
+++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir
@@ -26,30 +26,22 @@
         _8 = const false;                // scope 0 at $DIR/issue-41888.rs:7:9: 7:10
         StorageLive(_1);                 // scope 0 at $DIR/issue-41888.rs:7:9: 7:10
         StorageLive(_2);                 // scope 1 at $DIR/issue-41888.rs:8:8: 8:14
-        _2 = cond() -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14
+        _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14
                                          // mir::Constant
                                          // + span: $DIR/issue-41888.rs:8:8: 8:12
                                          // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41888.rs:6:1: 15:2
+    bb1: {
+        switchInt(_2) -> [false: bb2, otherwise: bb3]; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
     }
 
     bb2: {
-        switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
-    }
-
-    bb3 (cleanup): {
-        goto -> bb1;                     // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-    }
-
-    bb4: {
         _0 = const ();                   // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
-        goto -> bb11;                    // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
+        goto -> bb8;                     // scope 1 at $DIR/issue-41888.rs:8:5: 14:6
     }
 
-    bb5: {
+    bb3: {
         StorageLive(_3);                 // scope 1 at $DIR/issue-41888.rs:9:13: 9:20
         StorageLive(_4);                 // scope 1 at $DIR/issue-41888.rs:9:18: 9:19
         _4 = K;                          // scope 1 at $DIR/issue-41888.rs:9:18: 9:19
@@ -58,39 +50,35 @@
         goto -> bb14;                    // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
     }
 
-    bb6: {
-        goto -> bb8;                     // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
+    bb4: {
+        goto -> bb5;                     // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
     }
 
-    bb7 (cleanup): {
-        goto -> bb3;                     // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
-    }
-
-    bb8: {
+    bb5: {
         StorageDead(_3);                 // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
         _5 = discriminant(_1);           // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
-        switchInt(move _5) -> [0_isize: bb10, otherwise: bb9]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
+        switchInt(move _5) -> [0_isize: bb7, otherwise: bb6]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24
     }
 
-    bb9: {
+    bb6: {
         _0 = const ();                   // scope 1 at $DIR/issue-41888.rs:10:9: 13:10
-        goto -> bb11;                    // scope 1 at $DIR/issue-41888.rs:10:9: 13:10
+        goto -> bb8;                     // scope 1 at $DIR/issue-41888.rs:10:9: 13:10
     }
 
-    bb10: {
+    bb7: {
         StorageLive(_6);                 // scope 1 at $DIR/issue-41888.rs:10:21: 10:23
         _9 = const false;                // scope 1 at $DIR/issue-41888.rs:10:21: 10:23
         _6 = move ((_1 as F).0: K);      // scope 1 at $DIR/issue-41888.rs:10:21: 10:23
         _0 = const ();                   // scope 2 at $DIR/issue-41888.rs:10:29: 13:10
         StorageDead(_6);                 // scope 1 at $DIR/issue-41888.rs:13:9: 13:10
-        goto -> bb11;                    // scope 1 at $DIR/issue-41888.rs:10:9: 13:10
+        goto -> bb8;                     // scope 1 at $DIR/issue-41888.rs:10:9: 13:10
     }
 
-    bb11: {
-        goto -> bb21;                    // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+    bb8: {
+        goto -> bb20;                    // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
-    bb12: {
+    bb9: {
         _7 = const false;                // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
         _8 = const false;                // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
         _9 = const false;                // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
@@ -99,12 +87,24 @@
         return;                          // scope 0 at $DIR/issue-41888.rs:15:2: 15:2
     }
 
+    bb10 (cleanup): {
+        goto -> bb11;                    // scope 1 at $DIR/issue-41888.rs:9:19: 9:20
+    }
+
+    bb11 (cleanup): {
+        goto -> bb12;                    // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+    }
+
+    bb12 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-41888.rs:6:1: 15:2
+    }
+
     bb13 (cleanup): {
         _7 = const true;                 // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
         _8 = const true;                 // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
         _9 = const true;                 // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
         _1 = move _3;                    // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
-        goto -> bb7;                     // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
+        goto -> bb10;                    // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
     }
 
     bb14: {
@@ -112,46 +112,41 @@
         _8 = const true;                 // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
         _9 = const true;                 // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
         _1 = move _3;                    // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
-        goto -> bb6;                     // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
+        goto -> bb4;                     // scope 1 at $DIR/issue-41888.rs:9:9: 9:10
     }
 
     bb15: {
         _7 = const false;                // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-        goto -> bb12;                    // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        goto -> bb9;                     // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
     bb16 (cleanup): {
-        _7 = const false;                // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-        goto -> bb1;                     // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        goto -> bb12;                    // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
-    bb17 (cleanup): {
-        goto -> bb16;                    // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+    bb17: {
+        drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
-    bb18: {
-        drop(_1) -> [return: bb15, unwind: bb16]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+    bb18 (cleanup): {
+        drop(_1) -> bb12;                // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
-    bb19 (cleanup): {
-        drop(_1) -> bb16;                // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+    bb19: {
+        _10 = discriminant(_1);          // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
     bb20: {
-        _10 = discriminant(_1);          // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-        switchInt(move _10) -> [0_isize: bb15, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
-    bb21: {
-        switchInt(_7) -> [false: bb15, otherwise: bb20]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+    bb21 (cleanup): {
+        _11 = discriminant(_1);          // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 
     bb22 (cleanup): {
-        _11 = discriminant(_1);          // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-        switchInt(move _11) -> [0_isize: bb17, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
-    }
-
-    bb23 (cleanup): {
-        switchInt(_7) -> [false: bb16, otherwise: bb22]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
+        switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2
     }
 }
diff --git a/src/test/mir-opt/issue_49232.main.mir_map.0.mir b/src/test/mir-opt/issue_49232.main.mir_map.0.mir
index 8d76835..79f5495 100644
--- a/src/test/mir-opt/issue_49232.main.mir_map.0.mir
+++ b/src/test/mir-opt/issue_49232.main.mir_map.0.mir
@@ -17,70 +17,52 @@
     }
 
     bb1: {
-        falseUnwind -> [real: bb3, cleanup: bb4]; // scope 0 at $DIR/issue-49232.rs:6:5: 14:6
+        falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/issue-49232.rs:6:5: 14:6
     }
 
     bb2: {
-        goto -> bb14;                    // scope 0 at $DIR/issue-49232.rs:15:2: 15:2
-    }
-
-    bb3: {
         StorageLive(_2);                 // scope 0 at $DIR/issue-49232.rs:7:13: 7:19
         StorageLive(_3);                 // scope 0 at $DIR/issue-49232.rs:8:19: 8:23
         _3 = const true;                 // scope 0 at $DIR/issue-49232.rs:8:19: 8:23
         FakeRead(ForMatchedPlace, _3);   // scope 0 at $DIR/issue-49232.rs:8:19: 8:23
-        switchInt(_3) -> [false: bb5, otherwise: bb6]; // scope 0 at $DIR/issue-49232.rs:9:17: 9:22
+        switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue-49232.rs:9:17: 9:22
     }
 
-    bb4 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-49232.rs:5:1: 15:2
+    bb3: {
+        falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at $DIR/issue-49232.rs:9:17: 9:22
+    }
+
+    bb4: {
+        _0 = const ();                   // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
+        goto -> bb10;                    // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
     }
 
     bb5: {
-        falseEdge -> [real: bb7, imaginary: bb6]; // scope 0 at $DIR/issue-49232.rs:9:17: 9:22
+        _2 = const 4_i32;                // scope 0 at $DIR/issue-49232.rs:9:26: 9:27
+        goto -> bb8;                     // scope 0 at $DIR/issue-49232.rs:8:13: 11:14
     }
 
     bb6: {
-        _0 = const ();                   // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
-        goto -> bb8;                     // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
-    }
-
-    bb7: {
-        _2 = const 4_i32;                // scope 0 at $DIR/issue-49232.rs:9:26: 9:27
-        goto -> bb12;                    // scope 0 at $DIR/issue-49232.rs:8:13: 11:14
-    }
-
-    bb8: {
-        StorageDead(_3);                 // scope 0 at $DIR/issue-49232.rs:12:10: 12:11
-        goto -> bb9;                     // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
-    }
-
-    bb9: {
-        StorageDead(_2);                 // scope 0 at $DIR/issue-49232.rs:14:5: 14:6
-        goto -> bb2;                     // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
-    }
-
-    bb10: {
         unreachable;                     // scope 0 at $DIR/issue-49232.rs:10:25: 10:30
     }
 
-    bb11: {
-        goto -> bb12;                    // scope 0 at $DIR/issue-49232.rs:8:13: 11:14
+    bb7: {
+        goto -> bb8;                     // scope 0 at $DIR/issue-49232.rs:8:13: 11:14
     }
 
-    bb12: {
+    bb8: {
         FakeRead(ForLet, _2);            // scope 0 at $DIR/issue-49232.rs:7:13: 7:19
         StorageDead(_3);                 // scope 0 at $DIR/issue-49232.rs:12:10: 12:11
         StorageLive(_5);                 // scope 1 at $DIR/issue-49232.rs:13:9: 13:22
         StorageLive(_6);                 // scope 1 at $DIR/issue-49232.rs:13:14: 13:21
         _6 = &_2;                        // scope 1 at $DIR/issue-49232.rs:13:14: 13:21
-        _5 = std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb4]; // scope 1 at $DIR/issue-49232.rs:13:9: 13:22
+        _5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; // scope 1 at $DIR/issue-49232.rs:13:9: 13:22
                                          // mir::Constant
                                          // + span: $DIR/issue-49232.rs:13:9: 13:13
                                          // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb13: {
+    bb9: {
         StorageDead(_6);                 // scope 1 at $DIR/issue-49232.rs:13:21: 13:22
         StorageDead(_5);                 // scope 1 at $DIR/issue-49232.rs:13:22: 13:23
         _1 = const ();                   // scope 0 at $DIR/issue-49232.rs:6:10: 14:6
@@ -88,7 +70,13 @@
         goto -> bb1;                     // scope 0 at $DIR/issue-49232.rs:6:5: 14:6
     }
 
-    bb14: {
+    bb10: {
+        StorageDead(_3);                 // scope 0 at $DIR/issue-49232.rs:12:10: 12:11
+        StorageDead(_2);                 // scope 0 at $DIR/issue-49232.rs:14:5: 14:6
         return;                          // scope 0 at $DIR/issue-49232.rs:15:2: 15:2
     }
+
+    bb11 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-49232.rs:5:1: 15:2
+    }
 }
diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
index 137d9a8..c1421f2 100644
--- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
@@ -30,89 +30,89 @@
         StorageLive(_3);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
         StorageLive(_4);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
         _4 = Option::<u32>::None;        // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
-        _3 = <Option<u32> as Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        _3 = <Option<u32> as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:15: 9:20
                                          // + literal: Const { ty: fn(std::option::Option<u32>) -> std::result::Result<<std::option::Option<u32> as std::ops::Try>::Ok, <std::option::Option<u32> as std::ops::Try>::Error> {<std::option::Option<u32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-62289.rs:8:1: 10:2
+    bb1: {
+        StorageDead(_4);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        _5 = discriminant(_3);           // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
     }
 
     bb2: {
-        StorageDead(_4);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        _5 = discriminant(_3);           // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        switchInt(move _5) -> [0_isize: bb4, 1_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    }
-
-    bb3 (cleanup): {
-        drop(_2) -> bb1;                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
-    }
-
-    bb4: {
         StorageLive(_10);                // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
         (*_2) = _10;                     // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
         StorageDead(_10);                // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
         _1 = move _2;                    // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-        drop(_2) -> [return: bb12, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
     }
 
-    bb5: {
+    bb3: {
         unreachable;                     // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
     }
 
-    bb6: {
+    bb4: {
         StorageLive(_6);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
         _6 = ((_3 as Err).0: std::option::NoneError); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
         StorageLive(_8);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
         StorageLive(_9);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
         _9 = _6;                         // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        _8 = <NoneError as From<NoneError>>::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+        _8 = <NoneError as From<NoneError>>::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:19: 9:20
                                          // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {<std::option::NoneError as std::convert::From<std::option::NoneError>>::from}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb7: {
-        return;                          // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
-    }
-
-    bb8: {
+    bb5: {
         StorageDead(_9);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        _0 = <Option<Box<u32>> as Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+        _0 = <Option<Box<u32>> as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:15: 9:20
                                          // + literal: Const { ty: fn(<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::Error) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb9: {
+    bb6: {
         StorageDead(_8);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
         StorageDead(_6);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        drop(_2) -> bb10;                // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        drop(_2) -> bb9;                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+    }
+
+    bb7: {
+        StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
+        drop(_1) -> bb8;                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+    }
+
+    bb8: {
+        StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+        StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
+        goto -> bb10;                    // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+    }
+
+    bb9: {
+        StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+        StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
+        goto -> bb10;                    // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
     bb10: {
-        StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
-        StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
-        StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
-        goto -> bb7;                     // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        return;                          // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
     bb11 (cleanup): {
-        drop(_1) -> bb1;                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
-    }
-
-    bb12: {
-        StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
-        _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
         drop(_1) -> bb13;                // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
     }
 
-    bb13: {
-        StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
-        StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
-        goto -> bb7;                     // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+    bb12 (cleanup): {
+        drop(_2) -> bb13;                // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+    }
+
+    bb13 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-62289.rs:8:1: 10:2
     }
 }
diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir
index 29654c2..e19cd74 100644
--- a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir
@@ -12,14 +12,6 @@
         _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
         _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
         StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
-        goto -> bb2;                     // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
-    }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
-    }
-
-    bb2: {
         return;                          // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
     }
 }
diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir
index 29654c2..e19cd74 100644
--- a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir
+++ b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir
@@ -12,14 +12,6 @@
         _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:19:13: 19:14
         _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:19:46: 19:47
         StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:19:48: 19:49
-        goto -> bb2;                     // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
-    }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:19:1: 19:49
-    }
-
-    bb2: {
         return;                          // scope 0 at $DIR/issue-72181.rs:19:49: 19:49
     }
 }
diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir
index 972a36a..c9a2b9c 100644
--- a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir
@@ -12,20 +12,16 @@
         _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
         _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
         _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
-        assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
-    }
-
-    bb2: {
+    bb1: {
         _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
         StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
-        goto -> bb3;                     // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+        return;                          // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
     }
 
-    bb3: {
-        return;                          // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
     }
 }
diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir
index 972a36a..c9a2b9c 100644
--- a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir
+++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir
@@ -12,20 +12,16 @@
         _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:16:43: 16:44
         _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
         _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
-        assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
+        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
-    }
-
-    bb2: {
+    bb1: {
         _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:16:40: 16:47
         StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:16:48: 16:49
-        goto -> bb3;                     // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+        return;                          // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
     }
 
-    bb3: {
-        return;                          // scope 0 at $DIR/issue-72181.rs:16:49: 16:49
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:16:1: 16:49
     }
 }
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
index 89b6012..cf66a50 100644
--- a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
@@ -22,17 +22,13 @@
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
-        _1 = std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
                                          // mir::Constant
                                          // + span: $DIR/issue-72181.rs:24:13: 24:32
                                          // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
         StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
         StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
@@ -48,19 +44,19 @@
         _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
         _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
         _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
-        assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
     }
 
-    bb3: {
+    bb2: {
         _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
         StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
         StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
         _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
         StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
-        goto -> bb4;                     // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+        return;                          // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
     }
 
-    bb4: {
-        return;                          // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+    bb3 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
     }
 }
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
index 89b6012..cf66a50 100644
--- a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
+++ b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
@@ -22,17 +22,13 @@
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
-        _1 = std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
+        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
                                          // mir::Constant
                                          // + span: $DIR/issue-72181.rs:24:13: 24:32
                                          // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:24:34: 24:35
         StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:26:9: 26:10
         StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:26:14: 26:27
@@ -48,19 +44,19 @@
         _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:27:24: 27:25
         _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
         _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
-        assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
+        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26
     }
 
-    bb3: {
+    bb2: {
         _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:27:22: 27:28
         StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
         StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:27:30: 27:31
         _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:23:11: 28:2
         StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:28:1: 28:2
-        goto -> bb4;                     // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+        return;                          // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
     }
 
-    bb4: {
-        return;                          // scope 0 at $DIR/issue-72181.rs:28:2: 28:2
+    bb3 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181.rs:23:1: 28:2
     }
 }
diff --git a/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir
index 1821365..7571d7b 100644
--- a/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir
+++ b/src/test/mir-opt/issue_72181_1.f.mir_map.0.mir
@@ -13,25 +13,17 @@
         unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181-1.rs:10:1: 12:2
-    }
-
-    bb2: {
+    bb1: {
         unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15
     }
 
-    bb3: {
+    bb2: {
         StorageDead(_3);                 // scope 0 at $DIR/issue-72181-1.rs:11:14: 11:15
         unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2
     }
 
-    bb4: {
+    bb3: {
         StorageDead(_2);                 // scope 0 at $DIR/issue-72181-1.rs:12:1: 12:2
-        goto -> bb5;                     // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
-    }
-
-    bb5: {
         return;                          // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2
     }
 }
diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
index d9e5d2c..1fd91c2 100644
--- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
+++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
@@ -21,41 +21,37 @@
         StorageLive(_2);                 // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
         StorageLive(_3);                 // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
         _3 = ();                         // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
-        _2 = transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
+        _2 = transmute::<(), Void>(move _3) -> [return: bb1, unwind: bb4]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
                                          // mir::Constant
                                          // + span: $DIR/issue-72181-1.rs:17:9: 17:40
                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181-1.rs:15:1: 21:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_3);                 // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44
         FakeRead(ForLet, _2);            // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
         AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16
         StorageLive(_4);                 // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
         StorageLive(_5);                 // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
         _5 = move _2;                    // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8
-        f(move _5) -> bb1;               // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
+        f(move _5) -> bb4;               // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
                                          // mir::Constant
                                          // + span: $DIR/issue-72181-1.rs:20:5: 20:6
                                          // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb3: {
+    bb2: {
         StorageDead(_5);                 // scope 1 at $DIR/issue-72181-1.rs:20:8: 20:9
         StorageDead(_4);                 // scope 1 at $DIR/issue-72181-1.rs:20:9: 20:10
         StorageDead(_2);                 // scope 0 at $DIR/issue-72181-1.rs:21:1: 21:2
         unreachable;                     // scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2
     }
 
-    bb4: {
-        goto -> bb5;                     // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
+    bb3: {
+        return;                          // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
     }
 
-    bb5: {
-        return;                          // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2
+    bb4 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-72181-1.rs:15:1: 21:2
     }
 }
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
index f24bcfe..ef7c730 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
@@ -3,61 +3,65 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
-      let mut _1: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-      let _2: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-      let mut _4: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _7: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _8: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _9: i32;                     // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: &std::fmt::Arguments;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _11: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _12: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _13: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _14: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _15: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _17: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _18: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
+      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+      let _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+      let mut _5: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _6: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _9: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _10: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _11: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _12: &std::fmt::Arguments;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _13: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _14: &[&str; 3];             // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _16: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _17: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _18: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _19: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _20: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _21: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _22: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       scope 1 {
-          debug split => _2;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
-          let _3: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
+          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
+          let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
           scope 3 {
-              debug _prev => _3;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
-              let _5: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _6: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
+              let _7: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              let _8: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               scope 4 {
-                  debug left_val => _5;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _6;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  debug left_val => _7;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  debug right_val => _8;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   scope 5 {
-                      debug arg0 => _21;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                      debug arg1 => _24;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg0 => _25;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg1 => _28;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                       scope 6 {
-                          debug x => _21;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _20;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _19: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _20: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _21: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _25;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _24;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                       scope 8 {
-                          debug x => _24;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _23;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _22: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _23: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _24: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _28;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _27;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                   }
                   scope 10 {
-                      debug pieces => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      debug args => _27;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      let mut _25: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
-                      let mut _26: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
-                      let mut _27: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      debug args => _31;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
                   }
               }
           }
       }
       scope 2 {
-          debug v => _2;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+          debug v => _3;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
       }
       scope 7 {
       }
@@ -65,114 +69,125 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          discriminant(_1) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          _2 = ((_1 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          ((_3 as Some).0: i32) = _2;      // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          discriminant(_3) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
-          (_4.0: &i32) = &_2;              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
+          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:3:20: 3:21
+          StorageDead(_3);                 // scope 0 at $DIR/issue-73223.rs:3:20: 3:21
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
+          ((_4 as Some).0: i32) = _1;      // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
+          discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
+          (_5.0: &i32) = &_1;              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _6 = const main::promoted[1];    // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &i32
                                            // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) }
-          StorageLive(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _5 = (_4.0: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _6 = (_4.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_7);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_5.1: &i32) = move _6;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _7 = (_5.0: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _8 = (_5.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _9 = (*_5);                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _8 = Eq(move _9, const 1_i32);   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _7 = Not(move _8);               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(_7) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _11 = (*_7);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _9 = Not(move _10);              // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb1: {
-          StorageDead(_7);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
       }
   
       bb2: {
-          StorageLive(_11);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_13);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _14 = const main::promoted[0];   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
                                            // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
-          StorageLive(_13);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = _5;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_14.0: &&i32) = &_15;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = &_6;                       // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_14.1: &&i32) = move _16;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_16);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _21 = (_14.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _24 = (_14.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _20 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_16);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _18 = _7;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_17.0: &&i32) = &_18;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_19);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _20 = _8;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _19 = &_20;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_17.1: &&i32) = move _19;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _25 = (_17.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _28 = (_17.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _24 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_19);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _19 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _20) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_23);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _23 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb3: {
-          (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _21) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb4: {
-          (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _19; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_19);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _23 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_23);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_22);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _22 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _23) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_26);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _26 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb5: {
-          (_18.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb6: {
-          (_18.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _22; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_22);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _13 = [move _17, move _18];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_26);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _16 = [move _21, move _22];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _15 = &_16;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_30);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          discriminant(_30) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.0: &[&str]) = move _29;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_30);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _12 = &_13;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _27 = move _12 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_26);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          discriminant(_26) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_11.0: &[&str]) = move _25;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_11.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _26; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_11.2: &[std::fmt::ArgumentV1]) = move _27; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_26);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _10 = &_11;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          begin_panic_fmt(move _10);       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          begin_panic_fmt(move _12);       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/std/src/macros.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
index f24bcfe..ef7c730 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
@@ -3,61 +3,65 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
-      let mut _1: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-      let _2: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-      let mut _4: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _7: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _8: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _9: i32;                     // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: &std::fmt::Arguments;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _11: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _12: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _13: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _14: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let _15: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _17: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
-      let mut _18: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
+      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+      let _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+      let mut _5: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _6: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _9: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _10: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _11: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _12: &std::fmt::Arguments;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _13: std::fmt::Arguments;        // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _14: &[&str; 3];             // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _16: [std::fmt::ArgumentV1; 2];  // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _17: (&&i32, &&i32);         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _18: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _19: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let _20: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _21: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _22: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       scope 1 {
-          debug split => _2;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
-          let _3: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
+          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
+          let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
           scope 3 {
-              debug _prev => _3;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
-              let _5: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _6: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
+              let _7: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+              let _8: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               scope 4 {
-                  debug left_val => _5;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _6;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  debug left_val => _7;    // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                  debug right_val => _8;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                   scope 5 {
-                      debug arg0 => _21;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                      debug arg1 => _24;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg0 => _25;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                      debug arg1 => _28;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                       scope 6 {
-                          debug x => _21;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _20;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _19: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _20: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _21: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _25;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _24;  // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                       scope 8 {
-                          debug x => _24;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          debug f => _23;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                          let mut _22: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _23: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
-                          let mut _24: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          debug x => _28;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          debug f => _27;  // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                          let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
+                          let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL
                       }
                   }
                   scope 10 {
-                      debug pieces => _25; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      debug args => _27;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-                      let mut _25: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
-                      let mut _26: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
-                      let mut _27: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      debug args => _31;   // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+                      let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
+                      let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL
                   }
               }
           }
       }
       scope 2 {
-          debug v => _2;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+          debug v => _3;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
       }
       scope 7 {
       }
@@ -65,114 +69,125 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          discriminant(_1) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          _2 = ((_1 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          ((_3 as Some).0: i32) = _2;      // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          discriminant(_3) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
-          (_4.0: &i32) = &_2;              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_4.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
+          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:3:20: 3:21
+          StorageDead(_3);                 // scope 0 at $DIR/issue-73223.rs:3:20: 3:21
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
+          ((_4 as Some).0: i32) = _1;      // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
+          discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
+          (_5.0: &i32) = &_1;              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _6 = const main::promoted[1];    // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &i32
                                            // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) }
-          StorageLive(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _5 = (_4.0: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _6 = (_4.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_7);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_8);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_5.1: &i32) = move _6;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _7 = (_5.0: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _8 = (_5.1: &i32);               // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _9 = (*_5);                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _8 = Eq(move _9, const 1_i32);   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _7 = Not(move _8);               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(_7) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _11 = (*_7);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _10 = Eq(move _11, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_11);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _9 = Not(move _10);              // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_10);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          switchInt(_9) -> [false: bb1, otherwise: bb2]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb1: {
-          StorageDead(_7);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_5);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
       }
   
       bb2: {
-          StorageLive(_11);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _25 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_13);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _14 = const main::promoted[0];   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
                                            // + ty: &[&str; 3]
                                            // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) }
-          StorageLive(_13);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = _5;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_14.0: &&i32) = &_15;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = &_6;                       // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_14.1: &&i32) = move _16;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageDead(_16);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _21 = (_14.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _24 = (_14.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _20 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_16);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _18 = _7;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_17.0: &&i32) = &_18;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_19);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _20 = _8;                        // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _19 = &_20;                      // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_17.1: &&i32) = move _19;       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _25 = (_17.0: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _28 = (_17.1: &&i32);            // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          _24 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_19);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _19 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _20) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_23);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _23 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb3: {
-          (_17.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _21) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb4: {
-          (_17.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _19; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_19);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _23 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_23);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar(<ZST>)) }
-          StorageLive(_22);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _22 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _23) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageLive(_26);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _26 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb5: {
-          (_18.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _24) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
       bb6: {
-          (_18.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _22; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_22);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _13 = [move _17, move _18];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_26);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _16 = [move _21, move _22];      // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _15 = &_16;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_30);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          discriminant(_30) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.0: &[&str]) = move _29;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          StorageDead(_30);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _12 = &_13;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          _27 = move _12 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          StorageLive(_26);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          discriminant(_26) = 0;           // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_11.0: &[&str]) = move _25;     // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_11.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _26; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          (_11.2: &[std::fmt::ArgumentV1]) = move _27; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          StorageDead(_26);                // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _10 = &_11;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
-          begin_panic_fmt(move _10);       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          begin_panic_fmt(move _12);       // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/std/src/macros.rs:LL:COL
                                            // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar(<ZST>)) }
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
index b68fc83..9039735 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
@@ -106,7 +106,7 @@
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:4:17: 4:23
           StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
           StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:4:17: 4:23
+          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
       }
   
       bb2: {
@@ -153,14 +153,10 @@
           StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(_15) -> [false: bb4, otherwise: bb5]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          switchInt(_15) -> [false: bb3, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb3: {
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
-      }
-  
-      bb4: {
           _8 = const ();                   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -170,10 +166,10 @@
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
           StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:9:1: 9:2
           StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
       }
   
-      bb5: {
+      bb4: {
           StorageLive(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageLive(_20);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageLive(_21);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
@@ -224,24 +220,24 @@
           StorageLive(_46);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_47);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _47 = _40;                       // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb6: {
+      bb5: {
           StorageDead(_47);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_48);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_49);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _49 = _39;                       // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb7: {
+      bb6: {
           StorageDead(_49);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
@@ -260,24 +256,24 @@
           StorageLive(_50);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_51);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _51 = _43;                       // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb8: {
+      bb7: {
           StorageDead(_51);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_52);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_53);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _53 = _42;                       // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb9: {
+      bb8: {
           StorageDead(_53);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
index b68fc83..9039735 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
@@ -106,7 +106,7 @@
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:4:17: 4:23
           StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
           StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:4:17: 4:23
+          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
       }
   
       bb2: {
@@ -153,14 +153,10 @@
           StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(_15) -> [false: bb4, otherwise: bb5]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          switchInt(_15) -> [false: bb3, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       }
   
       bb3: {
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
-      }
-  
-      bb4: {
           _8 = const ();                   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -170,10 +166,10 @@
           _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
           StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:9:1: 9:2
           StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
       }
   
-      bb5: {
+      bb4: {
           StorageLive(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageLive(_20);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
           StorageLive(_21);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
@@ -224,24 +220,24 @@
           StorageLive(_46);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_47);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _47 = _40;                       // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb6: {
+      bb5: {
           StorageDead(_47);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_48);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_49);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _49 = _39;                       // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb7: {
+      bb6: {
           StorageDead(_49);                // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
@@ -260,24 +256,24 @@
           StorageLive(_50);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_51);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _51 = _43;                       // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb8: {
+      bb7: {
           StorageDead(_51);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_52);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           StorageLive(_53);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           _53 = _42;                       // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-          _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+          _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
                                            // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
       }
   
-      bb9: {
+      bb8: {
           StorageDead(_53);                // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
           (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
diff --git a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
index 9f9904b..05def56 100644
--- a/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
+++ b/src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
@@ -17,41 +17,41 @@
         StorageLive(_2);                 // scope 0 at $DIR/loop_test.rs:10:8: 10:12
         _2 = const true;                 // scope 0 at $DIR/loop_test.rs:10:8: 10:12
         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/loop_test.rs:10:8: 10:12
-        switchInt(_2) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/loop_test.rs:10:5: 12:6
+        switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/loop_test.rs:10:5: 12:6
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/loop_test.rs:6:1: 17:2
+    bb1: {
+        falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/loop_test.rs:10:5: 12:6
     }
 
     bb2: {
-        falseEdge -> [real: bb4, imaginary: bb3]; // scope 0 at $DIR/loop_test.rs:10:5: 12:6
-    }
-
-    bb3: {
         _1 = const ();                   // scope 0 at $DIR/loop_test.rs:10:5: 12:6
         StorageDead(_2);                 // scope 0 at $DIR/loop_test.rs:12:5: 12:6
         StorageDead(_1);                 // scope 0 at $DIR/loop_test.rs:12:5: 12:6
         StorageLive(_4);                 // scope 0 at $DIR/loop_test.rs:13:5: 16:6
-        goto -> bb5;                     // scope 0 at $DIR/loop_test.rs:13:5: 16:6
+        goto -> bb4;                     // scope 0 at $DIR/loop_test.rs:13:5: 16:6
     }
 
-    bb4: {
+    bb3: {
         _0 = const ();                   // scope 0 at $DIR/loop_test.rs:11:9: 11:15
         StorageDead(_2);                 // scope 0 at $DIR/loop_test.rs:12:5: 12:6
         StorageDead(_1);                 // scope 0 at $DIR/loop_test.rs:12:5: 12:6
         return;                          // scope 0 at $DIR/loop_test.rs:17:2: 17:2
     }
 
-    bb5: {
-        falseUnwind -> [real: bb6, cleanup: bb1]; // scope 0 at $DIR/loop_test.rs:13:5: 16:6
+    bb4: {
+        falseUnwind -> [real: bb5, cleanup: bb6]; // scope 0 at $DIR/loop_test.rs:13:5: 16:6
     }
 
-    bb6: {
+    bb5: {
         StorageLive(_6);                 // scope 0 at $DIR/loop_test.rs:14:13: 14:14
         _6 = const 1_i32;                // scope 0 at $DIR/loop_test.rs:14:17: 14:18
         FakeRead(ForLet, _6);            // scope 0 at $DIR/loop_test.rs:14:13: 14:14
         StorageDead(_6);                 // scope 0 at $DIR/loop_test.rs:16:5: 16:6
-        goto -> bb5;                     // scope 0 at $DIR/loop_test.rs:15:9: 15:17
+        goto -> bb4;                     // scope 0 at $DIR/loop_test.rs:1:1: 1:1
+    }
+
+    bb6 (cleanup): {
+        resume;                          // scope 0 at $DIR/loop_test.rs:6:1: 17:2
     }
 }
diff --git a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
index 8062f33..4e7cd77 100644
--- a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
+++ b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
@@ -32,54 +32,50 @@
   
       bb0: {
 -         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
--         switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
-+         switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
+-         switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
++         switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
       }
   
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/match-arm-scopes.rs:13:1: 18:2
+      bb1: {
+-         falseEdge -> [real: bb8, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:9: 15:22
++         switchInt((_2.1: bool)) -> [false: bb10, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
       }
   
       bb2: {
--         falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:15:9: 15:22
-+         switchInt((_2.1: bool)) -> [false: bb14, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
+-         switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
++         switchInt((_2.0: bool)) -> [false: bb3, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
       }
   
       bb3: {
--         switchInt((_2.1: bool)) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
-+         switchInt((_2.0: bool)) -> [false: bb4, otherwise: bb21]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
-      }
-  
-      bb4: {
--         falseEdge -> [real: bb18, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:15:25: 15:38
+-         falseEdge -> [real: bb14, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:15:25: 15:38
+-     }
+- 
+-     bb4: {
+-         switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
 -     }
 - 
 -     bb5: {
--         switchInt((_2.0: bool)) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
+-         falseEdge -> [real: bb22, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:9: 16:21
 -     }
 - 
 -     bb6: {
--         falseEdge -> [real: bb26, imaginary: bb7]; // scope 0 at $DIR/match-arm-scopes.rs:16:9: 16:21
--     }
-- 
--     bb7: {
           StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33
           _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33
           StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36
           _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36
--         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
-+         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+-         goto -> bb21;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb16;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+      }
+  
+-     bb7: {
++     bb4: {
+          _0 = const 1_i32;                // scope 1 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         drop(_7) -> [return: bb20, unwind: bb27]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
++         drop(_7) -> [return: bb15, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
       }
   
 -     bb8: {
 +     bb5: {
-          _0 = const 1_i32;                // scope 1 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         drop(_7) -> [return: bb24, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-+         drop(_7) -> [return: bb19, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-      }
-  
--     bb9: {
-+     bb6: {
           StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
           _6 = &(_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
           StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
@@ -90,52 +86,33 @@
           StorageLive(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
           _10 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
 -         FakeRead(ForMatchedPlace, _10);  // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
--         switchInt(_10) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
-+         switchInt(_10) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-         switchInt(_10) -> [false: bb10, otherwise: bb9]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(_10) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
       }
   
--     bb10: {
--         falseEdge -> [real: bb12, imaginary: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-     bb9: {
+-         falseEdge -> [real: bb11, imaginary: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
 -     }
 - 
--     bb11: {
-+     bb7: {
+-     bb10: {
++     bb6: {
           _9 = (*_6);                      // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71
           StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
--         switchInt(move _9) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
-+         switchInt(move _9) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-         switchInt(move _9) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(move _9) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+      }
+  
+-     bb11: {
++     bb7: {
+          _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
+          StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+          StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
++         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
       }
   
 -     bb12: {
 +     bb8: {
-          _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
-          StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
-          StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         goto -> bb15;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
-+         goto -> bb11;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
-      }
-  
--     bb13: {
-+     bb9: {
-          return;                          // scope 0 at $DIR/match-arm-scopes.rs:18:2: 18:2
-      }
-  
--     bb14 (cleanup): {
--         drop(_2) -> bb1;                 // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
-+     bb10 (cleanup): {
-+         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
-      }
-  
--     bb15: {
--         drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
-+     bb11: {
-+         drop(_2) -> [return: bb9, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
-      }
-  
--     bb16: {
-+     bb12: {
           StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
 -         FakeRead(ForMatchGuard, _3);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
 -         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
@@ -145,21 +122,21 @@
           _5 = (_2.1: bool);               // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
           StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
           _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
--         goto -> bb8;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
-+         goto -> bb5;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+-         goto -> bb7;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb4;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
       }
   
--     bb17: {
-+     bb13: {
+-     bb13: {
++     bb9: {
           StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
           StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
           StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         falseEdge -> [real: bb3, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
-+         goto -> bb2;                     // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-         falseEdge -> [real: bb2, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         goto -> bb1;                     // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
       }
   
--     bb18: {
-+     bb14: {
+-     bb14: {
++     bb10: {
           StorageLive(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
           _6 = &(_2.0: bool);              // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
           StorageLive(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
@@ -170,35 +147,33 @@
           StorageLive(_13);                // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
           _13 = _1;                        // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
 -         FakeRead(ForMatchedPlace, _13);  // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
--         switchInt(_13) -> [false: bb20, otherwise: bb19]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
-+         switchInt(_13) -> [false: bb15, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-         switchInt(_13) -> [false: bb16, otherwise: bb15]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(_13) -> [false: bb11, otherwise: bb12]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
       }
   
--     bb19: {
--         falseEdge -> [real: bb21, imaginary: bb20]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-     bb15: {
+-         falseEdge -> [real: bb17, imaginary: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
 -     }
 - 
--     bb20: {
-+     bb15: {
+-     bb16: {
++     bb11: {
           _12 = (*_6);                     // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71
           StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
--         switchInt(move _12) -> [false: bb23, otherwise: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
-+         switchInt(move _12) -> [false: bb18, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-         switchInt(move _12) -> [false: bb19, otherwise: bb18]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         switchInt(move _12) -> [false: bb14, otherwise: bb13]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
       }
   
--     bb21: {
-+     bb16: {
+-     bb17: {
++     bb12: {
           _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
           StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
           StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         goto -> bb15;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
-+         goto -> bb11;                    // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+-         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
++         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
       }
   
--     bb22: {
-+     bb17: {
+-     bb18: {
++     bb13: {
           StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
 -         FakeRead(ForMatchGuard, _3);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
 -         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
@@ -208,82 +183,98 @@
           _5 = (_2.0: bool);               // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
           StorageLive(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
           _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
--         goto -> bb8;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
-+         goto -> bb5;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+-         goto -> bb7;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb4;                     // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
       }
   
--     bb23: {
-+     bb18: {
+-     bb19: {
++     bb14: {
           StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
           StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
           StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         falseEdge -> [real: bb5, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
-+         goto -> bb3;                     // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+-         falseEdge -> [real: bb4, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++         goto -> bb2;                     // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
       }
   
--     bb24: {
-+     bb19: {
+-     bb20: {
++     bb15: {
           StorageDead(_7);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
           StorageDead(_5);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
           StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
           StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         goto -> bb28;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
-+         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+-         goto -> bb24;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb19;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
       }
   
--     bb25: {
-+     bb20: {
+-     bb21: {
++     bb16: {
           _0 = const 2_i32;                // scope 2 at $DIR/match-arm-scopes.rs:16:41: 16:42
--         drop(_16) -> [return: bb27, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
-+         drop(_16) -> [return: bb22, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
+-         drop(_16) -> [return: bb23, unwind: bb27]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
++         drop(_16) -> [return: bb18, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
       }
   
--     bb26: {
-+     bb21: {
+-     bb22: {
++     bb17: {
           StorageLive(_15);                // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
           _15 = (_2.1: bool);              // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
           StorageLive(_16);                // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
           _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
--         goto -> bb25;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
-+         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+-         goto -> bb21;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb16;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
       }
   
--     bb27: {
-+     bb22: {
+-     bb23: {
++     bb18: {
           StorageDead(_16);                // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
           StorageDead(_15);                // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
--         goto -> bb28;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
-+         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+-         goto -> bb24;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++         goto -> bb19;                    // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
       }
   
--     bb28: {
--         drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
-+     bb23: {
-+         goto -> bb29;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+-     bb24: {
+-         drop(_2) -> [return: bb26, unwind: bb28]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     bb19: {
++         goto -> bb26;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+      }
+  
+-     bb25: {
++     bb20: {
+          StorageDead(_8);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+          StorageDead(_6);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+-         drop(_2) -> [return: bb26, unwind: bb28]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++         drop(_2) -> [return: bb21, unwind: bb23]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+      }
+  
+-     bb26: {
++     bb21: {
+          return;                          // scope 0 at $DIR/match-arm-scopes.rs:18:2: 18:2
+      }
+  
+-     bb27 (cleanup): {
+-         drop(_2) -> bb28;                // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     bb22 (cleanup): {
++         goto -> bb27;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+      }
+  
+-     bb28 (cleanup): {
++     bb23 (cleanup): {
+          resume;                          // scope 0 at $DIR/match-arm-scopes.rs:13:1: 18:2
 +     }
 + 
-+     bb24 (cleanup): {
-+         goto -> bb1;                     // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++     bb24: {
++         goto -> bb21;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
 +     }
 + 
 +     bb25 (cleanup): {
-+         goto -> bb24;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
 +     }
 + 
 +     bb26: {
-+         goto -> bb9;                     // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++         goto -> bb24;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
 +     }
 + 
 +     bb27 (cleanup): {
-+         goto -> bb1;                     // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
-+     }
-+ 
-+     bb28 (cleanup): {
-+         goto -> bb27;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
-+     }
-+ 
-+     bb29: {
-+         goto -> bb26;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
       }
   }
   
diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
index e09d32c..2332e5b 100644
--- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
+++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
@@ -29,31 +29,27 @@
         _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         _3 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
-        switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
+        switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/match_false_edges.rs:14:1: 20:2
+    bb1: {
+        _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:18:17: 18:23
+        goto -> bb10;                    // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
     }
 
     bb2: {
-        _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:18:17: 18:23
-        goto -> bb11;                    // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
+        falseEdge -> [real: bb5, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
     }
 
     bb3: {
-        falseEdge -> [real: bb6, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16
+        falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:17:9: 17:16
     }
 
     bb4: {
-        falseEdge -> [real: bb10, imaginary: bb2]; // scope 0 at $DIR/match_false_edges.rs:17:9: 17:16
-    }
-
-    bb5: {
         unreachable;                     // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
     }
 
-    bb6: {
+    bb5: {
         StorageLive(_6);                 // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
         _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
                                          // ty::Const
@@ -65,17 +61,17 @@
         _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
         _4 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         StorageLive(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
-        _7 = guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
+        _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:16:20: 16:25
                                          // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb7: {
-        switchInt(move _7) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
+    bb6: {
+        switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
     }
 
-    bb8: {
+    bb7: {
         StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:36: 16:37
         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match_false_edges.rs:16:26: 16:27
         FakeRead(ForGuardBinding, _6);   // scope 0 at $DIR/match_false_edges.rs:16:26: 16:27
@@ -87,16 +83,16 @@
         StorageDead(_8);                 // scope 2 at $DIR/match_false_edges.rs:16:36: 16:37
         StorageDead(_5);                 // scope 0 at $DIR/match_false_edges.rs:16:36: 16:37
         StorageDead(_6);                 // scope 0 at $DIR/match_false_edges.rs:16:36: 16:37
-        goto -> bb11;                    // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
+        goto -> bb10;                    // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
+    }
+
+    bb8: {
+        StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:36: 16:37
+        StorageDead(_6);                 // scope 0 at $DIR/match_false_edges.rs:16:36: 16:37
+        goto -> bb3;                     // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
     }
 
     bb9: {
-        StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:36: 16:37
-        StorageDead(_6);                 // scope 0 at $DIR/match_false_edges.rs:16:36: 16:37
-        goto -> bb4;                     // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
-    }
-
-    bb10: {
         StorageLive(_9);                 // scope 0 at $DIR/match_false_edges.rs:17:14: 17:15
         _9 = ((_2 as Some).0: i32);      // scope 0 at $DIR/match_false_edges.rs:17:14: 17:15
         StorageLive(_10);                // scope 3 at $DIR/match_false_edges.rs:17:24: 17:25
@@ -104,13 +100,17 @@
         _1 = (const 2_i32, move _10);    // scope 3 at $DIR/match_false_edges.rs:17:20: 17:26
         StorageDead(_10);                // scope 3 at $DIR/match_false_edges.rs:17:25: 17:26
         StorageDead(_9);                 // scope 0 at $DIR/match_false_edges.rs:17:25: 17:26
-        goto -> bb11;                    // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
+        goto -> bb10;                    // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6
     }
 
-    bb11: {
+    bb10: {
         StorageDead(_2);                 // scope 0 at $DIR/match_false_edges.rs:19:6: 19:7
         StorageDead(_1);                 // scope 0 at $DIR/match_false_edges.rs:19:6: 19:7
         _0 = const ();                   // scope 0 at $DIR/match_false_edges.rs:14:28: 20:2
         return;                          // scope 0 at $DIR/match_false_edges.rs:20:2: 20:2
     }
+
+    bb11 (cleanup): {
+        resume;                          // scope 0 at $DIR/match_false_edges.rs:14:1: 20:2
+    }
 }
diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir
index a6c4925..c7b1cce 100644
--- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir
+++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir
@@ -28,22 +28,18 @@
         _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
         _3 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
-        switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
+        switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/match_false_edges.rs:25:1: 31:2
+    bb1: {
+        falseEdge -> [real: bb9, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:28:9: 28:13
     }
 
     bb2: {
-        falseEdge -> [real: bb10, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:28:9: 28:13
+        falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
     }
 
     bb3: {
-        falseEdge -> [real: bb6, imaginary: bb2]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16
-    }
-
-    bb4: {
         StorageLive(_9);                 // scope 0 at $DIR/match_false_edges.rs:29:14: 29:15
         _9 = ((_2 as Some).0: i32);      // scope 0 at $DIR/match_false_edges.rs:29:14: 29:15
         StorageLive(_10);                // scope 3 at $DIR/match_false_edges.rs:29:24: 29:25
@@ -51,29 +47,29 @@
         _1 = (const 2_i32, move _10);    // scope 3 at $DIR/match_false_edges.rs:29:20: 29:26
         StorageDead(_10);                // scope 3 at $DIR/match_false_edges.rs:29:25: 29:26
         StorageDead(_9);                 // scope 0 at $DIR/match_false_edges.rs:29:25: 29:26
-        goto -> bb11;                    // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
+        goto -> bb10;                    // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
     }
 
-    bb5: {
+    bb4: {
         unreachable;                     // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
     }
 
-    bb6: {
+    bb5: {
         StorageLive(_6);                 // scope 0 at $DIR/match_false_edges.rs:27:14: 27:15
         _6 = &((_2 as Some).0: i32);     // scope 0 at $DIR/match_false_edges.rs:27:14: 27:15
         _4 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27
         StorageLive(_7);                 // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27
-        _7 = guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27
+        _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:27:20: 27:25
                                          // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb7: {
-        switchInt(move _7) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27
+    bb6: {
+        switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27
     }
 
-    bb8: {
+    bb7: {
         StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:27:36: 27:37
         FakeRead(ForMatchGuard, _4);     // scope 0 at $DIR/match_false_edges.rs:27:26: 27:27
         FakeRead(ForGuardBinding, _6);   // scope 0 at $DIR/match_false_edges.rs:27:26: 27:27
@@ -85,24 +81,28 @@
         StorageDead(_8);                 // scope 2 at $DIR/match_false_edges.rs:27:36: 27:37
         StorageDead(_5);                 // scope 0 at $DIR/match_false_edges.rs:27:36: 27:37
         StorageDead(_6);                 // scope 0 at $DIR/match_false_edges.rs:27:36: 27:37
-        goto -> bb11;                    // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
+        goto -> bb10;                    // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
+    }
+
+    bb8: {
+        StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:27:36: 27:37
+        StorageDead(_6);                 // scope 0 at $DIR/match_false_edges.rs:27:36: 27:37
+        falseEdge -> [real: bb3, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27
     }
 
     bb9: {
-        StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:27:36: 27:37
-        StorageDead(_6);                 // scope 0 at $DIR/match_false_edges.rs:27:36: 27:37
-        falseEdge -> [real: bb4, imaginary: bb2]; // scope 0 at $DIR/match_false_edges.rs:27:20: 27:27
+        _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:28:17: 28:23
+        goto -> bb10;                    // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
     }
 
     bb10: {
-        _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:28:17: 28:23
-        goto -> bb11;                    // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6
-    }
-
-    bb11: {
         StorageDead(_2);                 // scope 0 at $DIR/match_false_edges.rs:30:6: 30:7
         StorageDead(_1);                 // scope 0 at $DIR/match_false_edges.rs:30:6: 30:7
         _0 = const ();                   // scope 0 at $DIR/match_false_edges.rs:25:29: 31:2
         return;                          // scope 0 at $DIR/match_false_edges.rs:31:2: 31:2
     }
+
+    bb11 (cleanup): {
+        resume;                          // scope 0 at $DIR/match_false_edges.rs:25:1: 31:2
+    }
 }
diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir
index 1d451cef..9b8ce2c 100644
--- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir
+++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir
@@ -39,49 +39,45 @@
         _2 = Option::<i32>::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
         FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
         _4 = discriminant(_2);           // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
-        switchInt(move _4) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
+        switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/match_false_edges.rs:34:1: 41:2
+    bb1: {
+        falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
     }
 
     bb2: {
-        falseEdge -> [real: bb10, imaginary: bb5]; // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
+        falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
     }
 
     bb3: {
-        falseEdge -> [real: bb6, imaginary: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17
-    }
-
-    bb4: {
         StorageLive(_14);                // scope 0 at $DIR/match_false_edges.rs:39:9: 39:11
         _14 = _2;                        // scope 0 at $DIR/match_false_edges.rs:39:9: 39:11
         _1 = const 4_i32;                // scope 5 at $DIR/match_false_edges.rs:39:15: 39:16
         StorageDead(_14);                // scope 0 at $DIR/match_false_edges.rs:39:15: 39:16
-        goto -> bb15;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
+        goto -> bb14;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
+    }
+
+    bb4: {
+        falseEdge -> [real: bb10, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:38:9: 38:16
     }
 
     bb5: {
-        falseEdge -> [real: bb11, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:38:9: 38:16
-    }
-
-    bb6: {
         StorageLive(_7);                 // scope 0 at $DIR/match_false_edges.rs:36:14: 36:16
         _7 = &((_2 as Some).0: i32);     // scope 0 at $DIR/match_false_edges.rs:36:14: 36:16
         _5 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
         StorageLive(_8);                 // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28
-        _8 = guard() -> [return: bb7, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28
+        _8 = guard() -> [return: bb6, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:36:21: 36:26
                                          // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb7: {
-        switchInt(move _8) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28
+    bb6: {
+        switchInt(move _8) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28
     }
 
-    bb8: {
+    bb7: {
         StorageDead(_8);                 // scope 0 at $DIR/match_false_edges.rs:36:32: 36:33
         FakeRead(ForMatchGuard, _5);     // scope 0 at $DIR/match_false_edges.rs:36:27: 36:28
         FakeRead(ForGuardBinding, _7);   // scope 0 at $DIR/match_false_edges.rs:36:27: 36:28
@@ -90,42 +86,42 @@
         _1 = const 1_i32;                // scope 2 at $DIR/match_false_edges.rs:36:32: 36:33
         StorageDead(_6);                 // scope 0 at $DIR/match_false_edges.rs:36:32: 36:33
         StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:36:32: 36:33
-        goto -> bb15;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
+        goto -> bb14;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
+    }
+
+    bb8: {
+        StorageDead(_8);                 // scope 0 at $DIR/match_false_edges.rs:36:32: 36:33
+        StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:36:32: 36:33
+        falseEdge -> [real: bb1, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28
     }
 
     bb9: {
-        StorageDead(_8);                 // scope 0 at $DIR/match_false_edges.rs:36:32: 36:33
-        StorageDead(_7);                 // scope 0 at $DIR/match_false_edges.rs:36:32: 36:33
-        falseEdge -> [real: bb2, imaginary: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:21: 36:28
-    }
-
-    bb10: {
         StorageLive(_9);                 // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
         _9 = _2;                         // scope 0 at $DIR/match_false_edges.rs:37:9: 37:11
         _1 = const 2_i32;                // scope 3 at $DIR/match_false_edges.rs:37:15: 37:16
         StorageDead(_9);                 // scope 0 at $DIR/match_false_edges.rs:37:15: 37:16
-        goto -> bb15;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
+        goto -> bb14;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
     }
 
-    bb11: {
+    bb10: {
         StorageLive(_11);                // scope 0 at $DIR/match_false_edges.rs:38:14: 38:15
         _11 = &((_2 as Some).0: i32);    // scope 0 at $DIR/match_false_edges.rs:38:14: 38:15
         _5 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26
         StorageLive(_12);                // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29
         StorageLive(_13);                // scope 0 at $DIR/match_false_edges.rs:38:27: 38:28
         _13 = (*_11);                    // scope 0 at $DIR/match_false_edges.rs:38:27: 38:28
-        _12 = guard2(move _13) -> [return: bb12, unwind: bb1]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29
+        _12 = guard2(move _13) -> [return: bb11, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:38:20: 38:26
                                          // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb12: {
+    bb11: {
         StorageDead(_13);                // scope 0 at $DIR/match_false_edges.rs:38:28: 38:29
-        switchInt(move _12) -> [false: bb14, otherwise: bb13]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29
+        switchInt(move _12) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29
     }
 
-    bb13: {
+    bb12: {
         StorageDead(_12);                // scope 0 at $DIR/match_false_edges.rs:38:33: 38:34
         FakeRead(ForMatchGuard, _5);     // scope 0 at $DIR/match_false_edges.rs:38:28: 38:29
         FakeRead(ForGuardBinding, _11);  // scope 0 at $DIR/match_false_edges.rs:38:28: 38:29
@@ -134,19 +130,23 @@
         _1 = const 3_i32;                // scope 4 at $DIR/match_false_edges.rs:38:33: 38:34
         StorageDead(_10);                // scope 0 at $DIR/match_false_edges.rs:38:33: 38:34
         StorageDead(_11);                // scope 0 at $DIR/match_false_edges.rs:38:33: 38:34
-        goto -> bb15;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
+        goto -> bb14;                    // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6
+    }
+
+    bb13: {
+        StorageDead(_12);                // scope 0 at $DIR/match_false_edges.rs:38:33: 38:34
+        StorageDead(_11);                // scope 0 at $DIR/match_false_edges.rs:38:33: 38:34
+        falseEdge -> [real: bb3, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29
     }
 
     bb14: {
-        StorageDead(_12);                // scope 0 at $DIR/match_false_edges.rs:38:33: 38:34
-        StorageDead(_11);                // scope 0 at $DIR/match_false_edges.rs:38:33: 38:34
-        falseEdge -> [real: bb4, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:38:20: 38:29
-    }
-
-    bb15: {
         StorageDead(_2);                 // scope 0 at $DIR/match_false_edges.rs:40:6: 40:7
         StorageDead(_1);                 // scope 0 at $DIR/match_false_edges.rs:40:6: 40:7
         _0 = const ();                   // scope 0 at $DIR/match_false_edges.rs:34:11: 41:2
         return;                          // scope 0 at $DIR/match_false_edges.rs:41:2: 41:2
     }
+
+    bb15 (cleanup): {
+        resume;                          // scope 0 at $DIR/match_false_edges.rs:34:1: 41:2
+    }
 }
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
index 3f01719..648cf24 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
@@ -2,83 +2,83 @@
 + // MIR for `bar` after MatchBranchSimplification
   
   fn bar(_1: i32) -> (bool, bool, bool, bool) {
-      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9
-      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43
-      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
-      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6
-      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7
-      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10
-      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13
-      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:12:8: 12:9
+      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:12:19: 12:43
+      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:6: 35:7
+      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10
+      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13
+      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16
       scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10
-          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
           scope 2 {
-              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10
-              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10
               scope 3 {
-                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10
-                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
                   scope 4 {
-                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:16:9: 16:10
                   }
               }
           }
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
-          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
-          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
-          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
-          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
--         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
-+         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
-+         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
-+         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
-+         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
-+         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
+          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+-         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
++         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
++         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
++         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
++         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
++         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
       }
   
       bb1: {
-          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21
-          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21
+          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
       }
   
       bb2: {
-          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
-          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
+          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
       }
   
       bb3: {
-          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7
-          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
-          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
-          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
-          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
-          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
-          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
-          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
-          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
-          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2
+          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7
+          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
+          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
+          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10
+          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10
+          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13
+          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13
+          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16
+          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16
+          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:36:2: 36:2
       }
   }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
index 3f01719..648cf24 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
@@ -2,83 +2,83 @@
 + // MIR for `bar` after MatchBranchSimplification
   
   fn bar(_1: i32) -> (bool, bool, bool, bool) {
-      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9
-      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43
-      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
-      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6
-      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7
-      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10
-      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13
-      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16
+      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:12:8: 12:9
+      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:12:19: 12:43
+      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:6: 35:7
+      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10
+      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13
+      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16
       scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10
-          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
           scope 2 {
-              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10
-              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10
               scope 3 {
-                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10
-                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
                   scope 4 {
-                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:16:9: 16:10
                   }
               }
           }
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10
-          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10
-          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10
-          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10
-          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
--         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
-+         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
-+         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
-+         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
-+         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
-+         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10
+          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10
+          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10
+          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10
+          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10
+          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
+-         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
++         _2 = Ne(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
++         _3 = Eq(_1, const 7_i32);        // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
++         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
++         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
++         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10
       }
   
       bb1: {
-          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21
-          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+          _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21
+          _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
       }
   
       bb2: {
-          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22
-          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
-          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6
+          _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22
+          _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21
+          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22
+          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21
+          goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6
       }
   
       bb3: {
-          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7
-          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
-          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7
-          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
-          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10
-          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
-          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13
-          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
-          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16
-          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17
-          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17
-          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2
+          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7
+          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
+          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7
+          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10
+          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10
+          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13
+          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13
+          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16
+          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16
+          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17
+          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17
+          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:36:1: 36:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:36:2: 36:2
       }
   }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
index 41f3603..a52abfb 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
@@ -2,17 +2,17 @@
 + // MIR for `foo` after MatchBranchSimplification
   
   fn foo(_1: Option<()>) -> () {
-      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11
-      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25
       let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 +         _2 = Eq(_3, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
       }
   
       bb1: {
@@ -26,17 +26,17 @@
       }
   
       bb3: {
-          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
       bb4: {
-          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
-          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
       bb5: {
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2
       }
   }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
index 41f3603..a52abfb 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
@@ -2,17 +2,17 @@
 + // MIR for `foo` after MatchBranchSimplification
   
   fn foo(_1: Option<()>) -> () {
-      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11
-      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25
+      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11
+      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25
       let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
+      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
+          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
+-         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
 +         _2 = Eq(_3, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26
++         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26
       }
   
       bb1: {
@@ -26,17 +26,17 @@
       }
   
       bb3: {
-          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
+          switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
       bb4: {
-          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
-          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6
+          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
+          goto -> bb5;                     // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6
       }
   
       bb5: {
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2
+          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2
       }
   }
   
diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs
index ebc88d2..54b79a8 100644
--- a/src/test/mir-opt/matches_reduce_branches.rs
+++ b/src/test/mir-opt/matches_reduce_branches.rs
@@ -1,3 +1,4 @@
+// compile-flags: -Zunsound-mir-opts
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
 // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/multiple_return_terminators.rs b/src/test/mir-opt/multiple_return_terminators.rs
new file mode 100644
index 0000000..b73a51d
--- /dev/null
+++ b/src/test/mir-opt/multiple_return_terminators.rs
@@ -0,0 +1,14 @@
+// compile-flags: -Z mir-opt-level=3
+// EMIT_MIR multiple_return_terminators.test.MultipleReturnTerminators.diff
+
+fn test(x: bool) {
+    if x {
+        // test
+    } else {
+        // test
+    }
+}
+
+fn main() {
+    test(true)
+}
diff --git a/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff
new file mode 100644
index 0000000..997c021
--- /dev/null
+++ b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff
@@ -0,0 +1,30 @@
+- // MIR for `test` before MultipleReturnTerminators
++ // MIR for `test` after MultipleReturnTerminators
+  
+  fn test(_1: bool) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/multiple_return_terminators.rs:4:9: 4:10
+      let mut _0: ();                      // return place in scope 0 at $DIR/multiple_return_terminators.rs:4:18: 4:18
+      let mut _2: bool;                    // in scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9
+          _2 = _1;                         // scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9
+          switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6
+      }
+  
+      bb1: {
+          _0 = const ();                   // scope 0 at $DIR/multiple_return_terminators.rs:7:12: 9:6
+          goto -> bb3;                     // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6
+      }
+  
+      bb2: {
+          _0 = const ();                   // scope 0 at $DIR/multiple_return_terminators.rs:5:10: 7:6
+          goto -> bb3;                     // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6
+      }
+  
+      bb3: {
+          StorageDead(_2);                 // scope 0 at $DIR/multiple_return_terminators.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/multiple_return_terminators.rs:10:2: 10:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 2885dd8..d8538a5 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -5,21 +5,21 @@
 | '_#1r | Local | ['_#1r]
 |
 | Inferred Region Values
-| '_#0r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#0r, '_#1r}
-| '_#1r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#1r}
+| '_#0r | U0 | {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0], '_#0r, '_#1r}
+| '_#1r | U0 | {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0], '_#1r}
 | '_#2r | U0 | {}
-| '_#3r | U0 | {bb2[0..=8], bb3[0], bb5[0..=2]}
-| '_#4r | U0 | {bb2[1..=8], bb3[0], bb5[0..=2]}
-| '_#5r | U0 | {bb2[4..=8], bb3[0], bb5[0..=2]}
+| '_#3r | U0 | {bb1[0..=8], bb2[0], bb4[0..=2]}
+| '_#4r | U0 | {bb1[1..=8], bb2[0], bb4[0..=2]}
+| '_#5r | U0 | {bb1[4..=8], bb2[0], bb4[0..=2]}
 |
 | Inference Constraints
-| '_#0r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]}
-| '_#1r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]}
-| '_#3r live at {bb2[0]}
-| '_#4r live at {bb2[1..=3]}
-| '_#5r live at {bb2[4..=8], bb3[0], bb5[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb2[0])
-| '_#4r: '_#5r due to Assignment at Single(bb2[3])
+| '_#0r live at {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0]}
+| '_#1r live at {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0]}
+| '_#3r live at {bb1[0]}
+| '_#4r live at {bb1[1..=3]}
+| '_#5r live at {bb1[4..=8], bb2[0], bb4[0..=2]}
+| '_#3r: '_#4r due to Assignment at Single(bb1[0])
+| '_#4r: '_#5r due to Assignment at Single(bb1[3])
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
@@ -52,66 +52,66 @@
         _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
         _4 = Len(_1);                    // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         _5 = Lt(_3, _4);                 // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
-        assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
+        assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb8]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
     }
 
-    bb1 (cleanup): {
-        resume;                          // bb1[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2
+    bb1: {
+        _2 = &'_#3r _1[_3];              // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18
+        FakeRead(ForLet, _2);            // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
+        StorageLive(_6);                 // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
+        _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
+        FakeRead(ForLet, _6);            // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
+        StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        FakeRead(ForMatchedPlace, _7);   // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb3, otherwise: bb2]; // bb1[8]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb2: {
-        _2 = &'_#3r _1[_3];              // bb2[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18
-        FakeRead(ForLet, _2);            // bb2[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
-        StorageLive(_6);                 // bb2[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
-        _6 = _2;                         // bb2[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
-        FakeRead(ForLet, _6);            // bb2[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
-        StorageLive(_7);                 // bb2[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        _7 = const Const(Value(Scalar(0x01)): bool); // bb2[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        FakeRead(ForMatchedPlace, _7);   // bb2[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb3]; // bb2[8]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+        falseEdge -> [real: bb4, imaginary: bb3]; // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb3: {
-        falseEdge -> [real: bb5, imaginary: bb4]; // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
-    }
-
-    bb4: {
-        StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        StorageLive(_10);                // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x00000016)): usize)) -> [return: bb6, unwind: bb8]; // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb5: {
-        StorageLive(_8);                 // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
-        StorageLive(_9);                 // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _9 = (*_6);                      // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+    bb4: {
+        StorageLive(_8);                 // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        StorageLive(_9);                 // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
+        _9 = (*_6);                      // bb4[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
+        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb5, unwind: bb8]; // bb4[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
     }
 
+    bb5: {
+        StorageDead(_9);                 // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
+        StorageDead(_8);                 // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
+        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        goto -> bb7;                     // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+    }
+
     bb6: {
-        StorageDead(_9);                 // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
-        StorageDead(_8);                 // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
-        goto -> bb8;                     // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+        StorageDead(_10);                // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
+        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        goto -> bb7;                     // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb7: {
-        StorageDead(_10);                // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
-        goto -> bb8;                     // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+        StorageDead(_6);                 // bb7[0]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_3);                 // bb7[1]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_2);                 // bb7[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_1);                 // bb7[3]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_7);                 // bb7[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        return;                          // bb7[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2
     }
 
-    bb8: {
-        StorageDead(_6);                 // bb8[0]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_3);                 // bb8[1]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_2);                 // bb8[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_1);                 // bb8[3]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_7);                 // bb8[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        return;                          // bb8[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2
+    bb8 (cleanup): {
+        resume;                          // bb8[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2
     }
 }
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index 3820f70..15aba40 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -5,21 +5,21 @@
 | '_#1r | Local | ['_#1r]
 |
 | Inferred Region Values
-| '_#0r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#0r, '_#1r}
-| '_#1r | U0 | {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5], '_#1r}
+| '_#0r | U0 | {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0], '_#0r, '_#1r}
+| '_#1r | U0 | {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0], '_#1r}
 | '_#2r | U0 | {}
-| '_#3r | U0 | {bb2[0..=8], bb3[0], bb5[0..=2]}
-| '_#4r | U0 | {bb2[1..=8], bb3[0], bb5[0..=2]}
-| '_#5r | U0 | {bb2[4..=8], bb3[0], bb5[0..=2]}
+| '_#3r | U0 | {bb1[0..=8], bb2[0], bb4[0..=2]}
+| '_#4r | U0 | {bb1[1..=8], bb2[0], bb4[0..=2]}
+| '_#5r | U0 | {bb1[4..=8], bb2[0], bb4[0..=2]}
 |
 | Inference Constraints
-| '_#0r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]}
-| '_#1r live at {bb0[0..=8], bb1[0], bb2[0..=8], bb3[0], bb4[0..=1], bb5[0..=3], bb6[0..=3], bb7[0..=2], bb8[0..=5]}
-| '_#3r live at {bb2[0]}
-| '_#4r live at {bb2[1..=3]}
-| '_#5r live at {bb2[4..=8], bb3[0], bb5[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb2[0])
-| '_#4r: '_#5r due to Assignment at Single(bb2[3])
+| '_#0r live at {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0]}
+| '_#1r live at {bb0[0..=8], bb1[0..=8], bb2[0], bb3[0..=1], bb4[0..=3], bb5[0..=3], bb6[0..=2], bb7[0..=5], bb8[0]}
+| '_#3r live at {bb1[0]}
+| '_#4r live at {bb1[1..=3]}
+| '_#5r live at {bb1[4..=8], bb2[0], bb4[0..=2]}
+| '_#3r: '_#4r due to Assignment at Single(bb1[0])
+| '_#4r: '_#5r due to Assignment at Single(bb1[3])
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
@@ -52,66 +52,66 @@
         _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17
         _4 = Len(_1);                    // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
         _5 = Lt(_3, _4);                 // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
-        assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
+        assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb8]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18
     }
 
-    bb1 (cleanup): {
-        resume;                          // bb1[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2
+    bb1: {
+        _2 = &'_#3r _1[_3];              // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18
+        FakeRead(ForLet, _2);            // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
+        StorageLive(_6);                 // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
+        _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
+        FakeRead(ForLet, _6);            // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
+        StorageLive(_7);                 // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        _7 = const Const(Value(Scalar(0x01)): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        FakeRead(ForMatchedPlace, _7);   // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
+        switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb3, otherwise: bb2]; // bb1[8]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb2: {
-        _2 = &'_#3r _1[_3];              // bb2[0]: scope 1 at $DIR/region-subtyping-basic.rs:18:13: 18:18
-        FakeRead(ForLet, _2);            // bb2[1]: scope 1 at $DIR/region-subtyping-basic.rs:18:9: 18:10
-        StorageLive(_6);                 // bb2[2]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
-        _6 = _2;                         // bb2[3]: scope 2 at $DIR/region-subtyping-basic.rs:19:13: 19:14
-        FakeRead(ForLet, _6);            // bb2[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
-        StorageLive(_7);                 // bb2[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        _7 = const Const(Value(Scalar(0x01)): bool); // bb2[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        FakeRead(ForMatchedPlace, _7);   // bb2[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
-        switchInt(_7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb3]; // bb2[8]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+        falseEdge -> [real: bb4, imaginary: bb3]; // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb3: {
-        falseEdge -> [real: bb5, imaginary: bb4]; // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
-    }
-
-    bb4: {
-        StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb7, unwind: bb1]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        StorageLive(_10);                // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(const Const(Value(Scalar(0x0000000000000016)): usize)) -> [return: bb6, unwind: bb8]; // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb5: {
-        StorageLive(_8);                 // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
-        StorageLive(_9);                 // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _9 = (*_6);                      // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb6, unwind: bb1]; // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+    bb4: {
+        StorageLive(_8);                 // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        StorageLive(_9);                 // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
+        _9 = (*_6);                      // bb4[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
+        _8 = Const(Value(Scalar(<ZST>)): fn(usize) -> bool {use_x})(move _9) -> [return: bb5, unwind: bb8]; // bb4[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
                                          // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
     }
 
+    bb5: {
+        StorageDead(_9);                 // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
+        StorageDead(_8);                 // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
+        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        goto -> bb7;                     // bb5[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+    }
+
     bb6: {
-        StorageDead(_9);                 // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
-        StorageDead(_8);                 // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
-        goto -> bb8;                     // bb6[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+        StorageDead(_10);                // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
+        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb6[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        goto -> bb7;                     // bb6[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb7: {
-        StorageDead(_10);                // bb7[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const Const(Value(Scalar(<ZST>)): ()); // bb7[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
-        goto -> bb8;                     // bb7[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
+        StorageDead(_6);                 // bb7[0]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_3);                 // bb7[1]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_2);                 // bb7[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_1);                 // bb7[3]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        StorageDead(_7);                 // bb7[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
+        return;                          // bb7[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2
     }
 
-    bb8: {
-        StorageDead(_6);                 // bb8[0]: scope 2 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_3);                 // bb8[1]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_2);                 // bb8[2]: scope 1 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_1);                 // bb8[3]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        StorageDead(_7);                 // bb8[4]: scope 0 at $DIR/region-subtyping-basic.rs:25:1: 25:2
-        return;                          // bb8[5]: scope 0 at $DIR/region-subtyping-basic.rs:25:2: 25:2
+    bb8 (cleanup): {
+        resume;                          // bb8[0]: scope 0 at $DIR/region-subtyping-basic.rs:16:1: 25:2
     }
 }
diff --git a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
index 5de8e98..1e4b329 100644
--- a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
@@ -41,12 +41,12 @@
         _3 = move ((_1 as Some).0: T);   // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:14: 9:15
         _0 = move _3;                    // scope 1 at $DIR/no-drop-for-inactive-variant.rs:9:20: 9:21
         StorageDead(_3);                 // scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:20: 9:21
-        _6 = discriminant(_1);           // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
+        _5 = discriminant(_1);           // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
         return;                          // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:2: 12:2
     }
 
     bb4 (cleanup): {
-        _5 = discriminant(_1);           // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
+        _7 = discriminant(_1);           // scope 0 at $DIR/no-drop-for-inactive-variant.rs:12:1: 12:2
         resume;                          // scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:1: 12:2
     }
 }
diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
index 495c7f2..bbb433d 100644
--- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
@@ -20,25 +20,21 @@
                                          // + span: $DIR/no-spurious-drop-after-call.rs:9:20: 9:22
                                          // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [], len: Size { raw: 0 } }, size: Size { raw: 0 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 0 }) }
         _3 = &(*_4);                     // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22
-        _2 = <str as ToString>::to_string(move _3) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34
+        _2 = <str as ToString>::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34
                                          // mir::Constant
                                          // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32
                                          // + literal: Const { ty: for<'r> fn(&'r str) -> std::string::String {<str as std::string::ToString>::to_string}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:1: 10:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_3);                 // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34
-        _1 = std::mem::drop::<String>(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35
+        _1 = std::mem::drop::<String>(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35
                                          // mir::Constant
                                          // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19
                                          // + literal: Const { ty: fn(std::string::String) {std::mem::drop::<std::string::String>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb3: {
+    bb2: {
         StorageDead(_2);                 // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35
         StorageDead(_4);                 // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:35: 9:36
         StorageDead(_1);                 // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:35: 9:36
@@ -46,7 +42,11 @@
         return;                          // scope 0 at $DIR/no-spurious-drop-after-call.rs:10:2: 10:2
     }
 
+    bb3 (cleanup): {
+        drop(_2) -> bb4;                 // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35
+    }
+
     bb4 (cleanup): {
-        drop(_2) -> bb1;                 // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35
+        resume;                          // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:1: 10:2
     }
 }
diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
index d8621b9..3983094 100644
--- a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
+++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff
@@ -12,8 +12,7 @@
       bb0: {
           StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _3 = discriminant(_1);           // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
-          _2 = Eq(_3, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb7;                     // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
+          switchInt(move _3) -> [0_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
       }
   
       bb1: {
@@ -29,8 +28,7 @@
       bb3: {
           StorageLive(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _5 = discriminant(_1);           // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
-          _4 = Eq(_5, const 1_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          goto -> bb10;                    // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
+          switchInt(move _5) -> [1_isize: bb9, otherwise: bb8]; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
       }
   
       bb4: {
@@ -64,9 +62,7 @@
       }
   
       bb10: {
--         _0 = Ne(_4, const false);        // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
-+         _0 = _4;                         // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
-          goto -> bb4;                     // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
+          switchInt(move _4) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
       }
   }
   
diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir
index 4641344..81f428d 100644
--- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir
+++ b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir
@@ -31,18 +31,18 @@
         drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:1: 8:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
         return;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:2: 8:2
     }
 
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:1: 8:2
+    }
+
     bb3 (cleanup): {
         (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8
-        drop(_1) -> bb1;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
+        drop(_1) -> bb2;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
     }
 
     bb4: {
@@ -50,6 +50,6 @@
         (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8
         StorageDead(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29
         _0 = const ();                   // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 8:2
-        drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
+        drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
     }
 }
diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir
index 4641344..81f428d 100644
--- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir
+++ b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir
@@ -31,18 +31,18 @@
         drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:1: 8:2
-    }
-
-    bb2: {
+    bb1: {
         StorageDead(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
         return;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:2: 8:2
     }
 
+    bb2 (cleanup): {
+        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:1: 8:2
+    }
+
     bb3 (cleanup): {
         (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8
-        drop(_1) -> bb1;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
+        drop(_1) -> bb2;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
     }
 
     bb4: {
@@ -50,6 +50,6 @@
         (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:5: 7:8
         StorageDead(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:7:28: 7:29
         _0 = const ();                   // scope 0 at $DIR/packed-struct-drop-aligned.rs:5:11: 8:2
-        drop(_1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
+        drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:8:1: 8:2
     }
 }
diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
index 52f422d..8c7d792 100644
--- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
@@ -70,29 +70,21 @@
         Retag(_7);                       // scope 1 at $DIR/retag.rs:32:29: 32:35
         _6 = &mut (*_7);                 // scope 1 at $DIR/retag.rs:32:29: 32:35
         Retag([2phase] _6);              // scope 1 at $DIR/retag.rs:32:29: 32:35
-        _3 = Test::foo(move _4, move _6) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/retag.rs:32:17: 32:36
+        _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb7]; // scope 1 at $DIR/retag.rs:32:17: 32:36
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:32:25: 32:28
                                          // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/retag.rs:29:1: 51:2
-    }
-
-    bb2: {
+    bb1: {
         Retag(_3);                       // scope 1 at $DIR/retag.rs:32:17: 32:36
         StorageDead(_6);                 // scope 1 at $DIR/retag.rs:32:35: 32:36
         StorageDead(_4);                 // scope 1 at $DIR/retag.rs:32:35: 32:36
         StorageDead(_7);                 // scope 1 at $DIR/retag.rs:32:36: 32:37
-        drop(_5) -> [return: bb4, unwind: bb1]; // scope 1 at $DIR/retag.rs:32:36: 32:37
+        drop(_5) -> [return: bb2, unwind: bb8]; // scope 1 at $DIR/retag.rs:32:36: 32:37
     }
 
-    bb3 (cleanup): {
-        drop(_5) -> bb1;                 // scope 1 at $DIR/retag.rs:32:36: 32:37
-    }
-
-    bb4: {
+    bb2: {
         StorageDead(_5);                 // scope 1 at $DIR/retag.rs:32:36: 32:37
         StorageLive(_8);                 // scope 2 at $DIR/retag.rs:33:13: 33:14
         StorageLive(_9);                 // scope 2 at $DIR/retag.rs:33:19: 33:20
@@ -138,10 +130,10 @@
         Retag(_18);                      // scope 6 at $DIR/retag.rs:44:16: 44:18
         _17 = &(*_18);                   // scope 6 at $DIR/retag.rs:44:16: 44:18
         Retag(_17);                      // scope 6 at $DIR/retag.rs:44:16: 44:18
-        _15 = move _16(move _17) -> bb5; // scope 6 at $DIR/retag.rs:44:14: 44:19
+        _15 = move _16(move _17) -> bb3; // scope 6 at $DIR/retag.rs:44:14: 44:19
     }
 
-    bb5: {
+    bb3: {
         Retag(_15);                      // scope 6 at $DIR/retag.rs:44:14: 44:19
         StorageDead(_17);                // scope 6 at $DIR/retag.rs:44:18: 44:19
         StorageDead(_16);                // scope 6 at $DIR/retag.rs:44:18: 44:19
@@ -166,25 +158,21 @@
         Retag(_23);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
         _22 = &(*_23);                   // scope 7 at $DIR/retag.rs:47:21: 47:23
         Retag(_22);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
-        _19 = Test::foo_shr(move _20, move _22) -> [return: bb6, unwind: bb7]; // scope 7 at $DIR/retag.rs:47:5: 47:24
+        _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb6]; // scope 7 at $DIR/retag.rs:47:5: 47:24
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:47:13: 47:20
                                          // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb6: {
+    bb4: {
         Retag(_19);                      // scope 7 at $DIR/retag.rs:47:5: 47:24
         StorageDead(_22);                // scope 7 at $DIR/retag.rs:47:23: 47:24
         StorageDead(_20);                // scope 7 at $DIR/retag.rs:47:23: 47:24
         StorageDead(_23);                // scope 7 at $DIR/retag.rs:47:24: 47:25
-        drop(_21) -> [return: bb8, unwind: bb1]; // scope 7 at $DIR/retag.rs:47:24: 47:25
+        drop(_21) -> [return: bb5, unwind: bb8]; // scope 7 at $DIR/retag.rs:47:24: 47:25
     }
 
-    bb7 (cleanup): {
-        drop(_21) -> bb1;                // scope 7 at $DIR/retag.rs:47:24: 47:25
-    }
-
-    bb8: {
+    bb5: {
         StorageDead(_21);                // scope 7 at $DIR/retag.rs:47:24: 47:25
         StorageDead(_19);                // scope 7 at $DIR/retag.rs:47:24: 47:25
         StorageLive(_25);                // scope 7 at $DIR/retag.rs:50:9: 50:11
@@ -200,4 +188,16 @@
         StorageDead(_1);                 // scope 0 at $DIR/retag.rs:51:1: 51:2
         return;                          // scope 0 at $DIR/retag.rs:51:2: 51:2
     }
+
+    bb6 (cleanup): {
+        drop(_21) -> bb8;                // scope 7 at $DIR/retag.rs:47:24: 47:25
+    }
+
+    bb7 (cleanup): {
+        drop(_5) -> bb8;                 // scope 1 at $DIR/retag.rs:32:36: 32:37
+    }
+
+    bb8 (cleanup): {
+        resume;                          // scope 0 at $DIR/retag.rs:29:1: 51:2
+    }
 }
diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir
index 64ca4b5..5bcb20c 100644
--- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir
@@ -6,32 +6,24 @@
 
     bb0: {
         FakeRead(ForMatchedPlace, _1);   // scope 0 at $DIR/simple-match.rs:6:11: 6:12
-        switchInt(_1) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
+        switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/simple-match.rs:5:1: 10:2
+    bb1: {
+        falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
     }
 
     bb2: {
-        falseEdge -> [real: bb4, imaginary: bb3]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
+        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:8:14: 8:16
+        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
     }
 
     bb3: {
-        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:8:14: 8:16
-        goto -> bb5;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
+        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:7:17: 7:19
+        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
     }
 
     bb4: {
-        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:7:17: 7:19
-        goto -> bb5;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
-    }
-
-    bb5: {
-        goto -> bb6;                     // scope 0 at $DIR/simple-match.rs:10:2: 10:2
-    }
-
-    bb6: {
         return;                          // scope 0 at $DIR/simple-match.rs:10:2: 10:2
     }
 }
diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir
index 64ca4b5..5bcb20c 100644
--- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir
+++ b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir
@@ -6,32 +6,24 @@
 
     bb0: {
         FakeRead(ForMatchedPlace, _1);   // scope 0 at $DIR/simple-match.rs:6:11: 6:12
-        switchInt(_1) -> [false: bb3, otherwise: bb2]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
+        switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/simple-match.rs:5:1: 10:2
+    bb1: {
+        falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
     }
 
     bb2: {
-        falseEdge -> [real: bb4, imaginary: bb3]; // scope 0 at $DIR/simple-match.rs:7:9: 7:13
+        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:8:14: 8:16
+        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
     }
 
     bb3: {
-        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:8:14: 8:16
-        goto -> bb5;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
+        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:7:17: 7:19
+        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
     }
 
     bb4: {
-        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:7:17: 7:19
-        goto -> bb5;                     // scope 0 at $DIR/simple-match.rs:6:5: 9:6
-    }
-
-    bb5: {
-        goto -> bb6;                     // scope 0 at $DIR/simple-match.rs:10:2: 10:2
-    }
-
-    bb6: {
         return;                          // scope 0 at $DIR/simple-match.rs:10:2: 10:2
     }
 }
diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs
index 9d81b7f..a7df786 100644
--- a/src/test/mir-opt/simplify-arm.rs
+++ b/src/test/mir-opt/simplify-arm.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=2
+// compile-flags: -Z mir-opt-level=2 -Zunsound-mir-opts
 // EMIT_MIR simplify_arm.id.SimplifyArmIdentity.diff
 // EMIT_MIR simplify_arm.id.SimplifyBranchSame.diff
 // EMIT_MIR simplify_arm.id_result.SimplifyArmIdentity.diff
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
index cf8940e..84f57de 100644
--- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
+++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
@@ -1,3 +1,5 @@
+// compile-flags: -Zunsound-mir-opts
+
 fn map(x: Option<Box<()>>) -> Option<Box<()>> {
     match x {
         None => None,
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
index 063f849..a811a2c 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
@@ -29,7 +29,7 @@
               scope 8 {
 -                 debug v => _8;           // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 +                 debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify-arm.rs:24:14: 24:15
+                  let mut _12: i32;        // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
               }
           }
       }
@@ -92,7 +92,7 @@
 +         _0 = move _3;                    // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
           StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
       }
   
       bb4: {
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
index 7c7b1b6..b0cc3e8 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
@@ -25,7 +25,7 @@
               }
               scope 8 {
                   debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify-arm.rs:24:14: 24:15
+                  let mut _12: i32;        // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
               }
           }
       }
@@ -66,7 +66,7 @@
 -         _0 = move _3;                    // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 -         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
 -         StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+-         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
 -     }
 - 
 -     bb4: {
diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
index ede081f..6274305 100644
--- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
+++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
@@ -13,40 +13,40 @@
 - 
 -     bb1: {
           StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
--         _2 = bar() -> bb3;               // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
+-         _2 = bar() -> bb2;               // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
 +         _2 = bar() -> bb1;               // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
                                            // mir::Constant
                                            // + span: $DIR/simplify_cfg.rs:7:12: 7:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
--     bb2 (cleanup): {
--         resume;                          // scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
+-     bb2: {
+-         nop;                             // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
+-         switchInt(_2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
 +     bb1: {
 +         switchInt(_2) -> [false: bb2, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
       }
   
 -     bb3: {
--         nop;                             // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
--         switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
+-         goto -> bb5;                     // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
 -     }
 - 
 -     bb4: {
--         goto -> bb6;                     // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
--     }
-- 
--     bb5: {
 +     bb2: {
           _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
           StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6
           goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
       }
   
--     bb6: {
+-     bb5: {
 +     bb3: {
           _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
           StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6
           return;                          // scope 0 at $DIR/simplify_cfg.rs:11:2: 11:2
+-     }
+- 
+-     bb6 (cleanup): {
+-         resume;                          // scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
index e8cdd39..9a6afc5 100644
--- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
+++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
@@ -9,78 +9,70 @@
   
       bb0: {
 -         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
-+         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
++         falseUnwind -> [real: bb1, cleanup: bb6]; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
       }
   
       bb1: {
--         falseUnwind -> [real: bb3, cleanup: bb4]; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
+-         falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
 -     }
 - 
 -     bb2: {
--         goto -> bb13;                    // scope 0 at $DIR/simplify_cfg.rs:11:2: 11:2
--     }
-- 
--     bb3: {
           StorageLive(_2);                 // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
--         _2 = bar() -> [return: bb5, unwind: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
-+         _2 = bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
+-         _2 = bar() -> [return: bb3, unwind: bb11]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
++         _2 = bar() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
                                            // mir::Constant
                                            // + span: $DIR/simplify_cfg.rs:7:12: 7:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
--     bb4 (cleanup): {
-+     bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
+-     bb3: {
++     bb2: {
+          FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
+-         switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
++         switchInt(_2) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
+      }
+  
+-     bb4: {
+-         falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
++     bb3: {
++         falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
       }
   
 -     bb5: {
-+     bb3: {
-          FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/simplify_cfg.rs:7:12: 7:17
--         switchInt(_2) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
-+         switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
-      }
-  
--     bb6: {
--         falseEdge -> [real: bb8, imaginary: bb7]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
 +     bb4: {
-+         falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
-      }
-  
--     bb7: {
-+     bb5: {
           _1 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
--         goto -> bb12;                    // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
+-         goto -> bb9;                     // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
 +         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6
 +         goto -> bb0;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
       }
   
--     bb8: {
-+     bb6: {
+-     bb6: {
++     bb5: {
           _0 = const ();                   // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
--         goto -> bb9;                     // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
+-         goto -> bb10;                    // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
+-     }
+- 
+-     bb7: {
+-         unreachable;                     // scope 0 at $DIR/simplify_cfg.rs:7:18: 9:10
+-     }
+- 
+-     bb8: {
+-         goto -> bb9;                     // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
 -     }
 - 
 -     bb9: {
           StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6
--         goto -> bb2;                     // scope 0 at $DIR/simplify_cfg.rs:8:13: 8:18
--     }
-- 
--     bb10: {
--         unreachable;                     // scope 0 at $DIR/simplify_cfg.rs:7:18: 9:10
--     }
-- 
--     bb11: {
--         goto -> bb12;                    // scope 0 at $DIR/simplify_cfg.rs:7:9: 9:10
--     }
-- 
--     bb12: {
--         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6
 -         goto -> bb1;                     // scope 0 at $DIR/simplify_cfg.rs:6:5: 10:6
 -     }
 - 
--     bb13: {
+-     bb10: {
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_cfg.rs:10:5: 10:6
           return;                          // scope 0 at $DIR/simplify_cfg.rs:11:2: 11:2
       }
+  
+-     bb11 (cleanup): {
++     bb6 (cleanup): {
+          resume;                          // scope 0 at $DIR/simplify_cfg.rs:5:1: 11:2
+      }
   }
   
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
index 68a113f..760fb74 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
@@ -2,25 +2,25 @@
 + // MIR for `map` after SimplifyLocals
   
   fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
-      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
--     let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
--     let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
--     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
--     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
--     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
--     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9
+      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46
+-     let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+-     let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
+-     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26
+-     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
+-     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
+-     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
       scope 1 {
-          debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+          debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
       }
   
       bb0: {
--         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
--         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
--         _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
-          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
--         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
-          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
+-         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+-         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+-         _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+-         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
index 68a113f..760fb74 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
@@ -2,25 +2,25 @@
 + // MIR for `map` after SimplifyLocals
   
   fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9
-      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46
--     let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
--     let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
--     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26
--     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
--     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
--     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
+      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9
+      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46
+-     let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+-     let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
+-     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26
+-     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
+-     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
+-     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
       scope 1 {
-          debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15
+          debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
       }
   
       bb0: {
--         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
--         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
--         _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13
-          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27
--         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2
-          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2
+-         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+-         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+-         _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+-         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs
index fca80be..eb307de 100644
--- a/src/test/mir-opt/simplify_try.rs
+++ b/src/test/mir-opt/simplify_try.rs
@@ -1,3 +1,4 @@
+// compile-flags: -Zunsound-mir-opts
 // EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff
 // EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir
 // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir
diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
index 187a3cf..12a6617 100644
--- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
+++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
@@ -2,35 +2,35 @@
 + // MIR for `try_identity` after DestinationPropagation
   
   fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
-      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
-      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
-      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
+      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
+      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
+      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10
+      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9
       scope 1 {
-          debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+          debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
       }
       scope 2 {
-          debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
+          debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
           scope 3 {
               scope 7 {
                   debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
               }
               scope 8 {
                   debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
+                  let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
               }
           }
       }
       scope 4 {
-          debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
+          debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
           scope 5 {
           }
       }
@@ -40,33 +40,29 @@
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
--         StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
--         StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
--         _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:8:9: 8:10
+-         StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+-         StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
+-         _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
 -         _3 = move _4;                    // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
--         StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
--         _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-+         _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+-         StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+-         _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
++         nop;                             // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
++         nop;                             // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
++         _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
 +         nop;                             // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-+         _5 = discriminant(_0);           // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-          goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
++         nop;                             // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
++         _5 = discriminant(_0);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+          goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
       }
   
       bb1: {
--         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
--         StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
-+         nop;                             // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
-          goto -> bb2;                     // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
-      }
-  
-      bb2: {
-          return;                          // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+-         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
++         nop;                             // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
++         nop;                             // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
index 0c68768..534836e 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
@@ -2,25 +2,25 @@
 + // MIR for `try_identity` after SimplifyArmIdentity
   
   fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
-      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
-      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
-      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
+      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
+      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
+      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10
+      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9
       scope 1 {
--         debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
-+         debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+-         debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
++         debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
       }
       scope 2 {
--         debug err => _6;                 // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
-+         debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
+-         debug err => _6;                 // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
++         debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
           scope 3 {
               scope 7 {
 -                 debug t => _9;           // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
@@ -29,13 +29,13 @@
               scope 8 {
 -                 debug v => _8;           // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 +                 debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
+                  let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
               }
           }
       }
       scope 4 {
--         debug val => _10;                // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
-+         debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
+-         debug val => _10;                // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
++         debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
           scope 5 {
           }
       }
@@ -44,55 +44,51 @@
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
-          StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-          StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-          _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:8:9: 8:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+          StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
+          _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
           _3 = move _4;                    // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-          _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-          switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+          StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+          switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
       }
   
       bb1: {
--         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
--         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
--         _2 = _10;                        // scope 5 at $DIR/simplify_try.rs:7:13: 7:15
--         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-+         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
-          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
--         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:8:8: 8:9
--         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:8:8: 8:9
--         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
--         discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
--         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:8:9: 8:10
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
-          goto -> bb3;                     // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+-         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+-         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+-         _2 = _10;                        // scope 5 at $DIR/simplify_try.rs:8:13: 8:15
+-         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
++         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
+-         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:9:8: 9:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:9:8: 9:9
+-         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
+-         discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:9:9: 9:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
       }
   
       bb2: {
--         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
--         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
--         StorageLive(_8);                 // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
--         StorageLive(_9);                 // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
--         _9 = _6;                         // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
+-         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+-         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+-         StorageLive(_8);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
+-         StorageLive(_9);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
+-         _9 = _6;                         // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
 -         _8 = move _9;                    // scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
--         StorageDead(_9);                 // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
+-         StorageDead(_9);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
 -         StorageLive(_12);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 -         _12 = move _8;                   // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 -         ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 -         discriminant(_0) = 1;            // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
 -         StorageDead(_12);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
--         StorageDead(_8);                 // scope 3 at $DIR/simplify_try.rs:7:14: 7:15
--         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+-         StorageDead(_8);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
+-         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
 +         _0 = move _3;                    // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
-          goto -> bb3;                     // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-      }
-  
-      bb3: {
-          return;                          // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
+          return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
index 9428d30..d2e37bf 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
@@ -1,35 +1,35 @@
 // MIR for `try_identity` after SimplifyBranchSame
 
 fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
-    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
-    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
-    let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
-    let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-    let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-    let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-    let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-    let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-    let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-    let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-    let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-    let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
+    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
+    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
+    let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10
+    let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+    let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14
+    let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+    let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+    let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+    let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+    let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+    let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+    let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9
     scope 1 {
-        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
     }
     scope 2 {
-        debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
+        debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
         scope 3 {
             scope 7 {
                 debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
             }
             scope 8 {
                 debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
+                let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
             }
         }
     }
     scope 4 {
-        debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
+        debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
         scope 5 {
         }
     }
@@ -38,24 +38,20 @@
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
-        StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-        StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-        _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
+        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:8:9: 8:10
+        StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
+        StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
+        _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
         _3 = move _4;                    // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-        _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-        goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
+        StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+        _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+        goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
     }
 
     bb1: {
-        _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
-        StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
-        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
-        goto -> bb2;                     // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
-    }
-
-    bb2: {
-        return;                          // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+        _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
+        StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
+        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
+        return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
     }
 }
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
index a25472f..508f270 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
@@ -1,13 +1,13 @@
 // MIR for `try_identity` after SimplifyLocals
 
 fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
-    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
-    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
+    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
+    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
     scope 1 {
-        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
+        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
     }
     scope 2 {
-        debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
+        debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
         scope 3 {
             scope 7 {
                 debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
@@ -18,7 +18,7 @@
         }
     }
     scope 4 {
-        debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
+        debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
         scope 5 {
         }
     }
@@ -27,7 +27,7 @@
     }
 
     bb0: {
-        _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-        return;                          // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
+        _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
+        return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
     }
 }
diff --git a/src/test/mir-opt/simplify_try_if_let.rs b/src/test/mir-opt/simplify_try_if_let.rs
index 0c4d8c8..fba67de 100644
--- a/src/test/mir-opt/simplify_try_if_let.rs
+++ b/src/test/mir-opt/simplify_try_if_let.rs
@@ -1,4 +1,7 @@
-// compile-flags: -Zmir-opt-level=1
+// compile-flags: -Zmir-opt-level=1 -Zunsound-mir-opts
+// ignore-test
+// FIXME: the pass is unsound and causes ICEs in the MIR validator
+
 // EMIT_MIR simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff
 
 use std::ptr::NonNull;
@@ -19,7 +22,7 @@
 
     pub fn append(&mut self, other: &mut Self) {
         match self.tail {
-            None => { },
+            None => {}
             Some(mut tail) => {
                 // `as_mut` is okay here because we have exclusive access to the entirety
                 // of both lists.
diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html
index 8f6b130..8e52680 100644
--- a/src/test/mir-opt/spanview_block.main.mir_map.0.html
+++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
+<title>spanview_block.main.mir_map.0</title>
+<style>
     .line {
         counter-increment: line;
     }
@@ -56,12 +56,11 @@
         /* requires hover over a span ONLY on its first line */
         display: inline-block;
     }
-    </style>
+</style>
 </head>
 <body>
 <div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0: $DIR/spanview-block.rs:5:11: 5:13:
     5:11-5:13: Assign: _0 = const ()
-    5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">0⦊</span>{}<span class="annotation">⦉0</span></span></span><span><span class="code odd" style="--layer: 1" title="2: $DIR/spanview-block.rs:5:13: 5:13:
-    5:13-5:13: Return: return"><span class="annotation">2⦊</span>‸<span class="annotation">⦉2</span></span></span></span></div>
+    5:13-5:13: Return: return"><span class="annotation">0⦊</span>{}<span class="annotation">⦉0</span></span></span></span></div>
 </body>
 </html>
diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir
deleted file mode 100644
index 8f6b130..0000000
--- a/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
-    .line {
-        counter-increment: line;
-    }
-    .line:before {
-        content: counter(line) ": ";
-        font-family: Menlo, Monaco, monospace;
-        font-style: italic;
-        width: 3.8em;
-        display: inline-block;
-        text-align: right;
-        filter: opacity(50%);
-        -webkit-user-select: none;
-    }
-    .code {
-        color: #dddddd;
-        background-color: #222222;
-        font-family: Menlo, Monaco, monospace;
-        line-height: 1.4em;
-        border-bottom: 2px solid #222222;
-        white-space: pre;
-        display: inline-block;
-    }
-    .odd {
-        background-color: #55bbff;
-        color: #223311;
-    }
-    .even {
-        background-color: #ee7756;
-        color: #551133;
-    }
-    .code {
-        --index: calc(var(--layer) - 1);
-        padding-top: calc(var(--index) * 0.15em);
-        filter:
-            hue-rotate(calc(var(--index) * 25deg))
-            saturate(calc(100% - (var(--index) * 2%)))
-            brightness(calc(100% - (var(--index) * 1.5%)));
-    }
-    .annotation {
-        color: #4444ff;
-        font-family: monospace;
-        font-style: italic;
-        display: none;
-        -webkit-user-select: none;
-    }
-    body:active .annotation {
-        /* requires holding mouse down anywhere on the page */
-        display: inline-block;
-    }
-    span:hover .annotation {
-        /* requires hover over a span ONLY on its first line */
-        display: inline-block;
-    }
-    </style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0: $DIR/spanview-block.rs:5:11: 5:13:
-    5:11-5:13: Assign: _0 = const ()
-    5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">0⦊</span>{}<span class="annotation">⦉0</span></span></span><span><span class="code odd" style="--layer: 1" title="2: $DIR/spanview-block.rs:5:13: 5:13:
-    5:13-5:13: Return: return"><span class="annotation">2⦊</span>‸<span class="annotation">⦉2</span></span></span></span></div>
-</body>
-</html>
diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html
index 072d224..abbff22 100644
--- a/src/test/mir-opt/spanview_statement.main.mir_map.0.html
+++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
+<title>spanview_statement.main.mir_map.0</title>
+<style>
     .line {
         counter-increment: line;
     }
@@ -56,12 +56,11 @@
         /* requires hover over a span ONLY on its first line */
         display: inline-block;
     }
-    </style>
+</style>
 </head>
 <body>
 <div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0[0]: $DIR/spanview-statement.rs:5:11: 5:13:
-    5:11-5:13: Assign: _0 = const ()"><span class="annotation">0[0]⦊</span>{}<span class="annotation">⦉0[0]</span></span></span><span><span class="code odd" style="--layer: 1" title="0:Goto: $DIR/spanview-statement.rs:5:13: 5:13:
-    5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">0:Goto⦊</span>‸<span class="annotation">⦉0:Goto</span></span></span><span><span class="code even" style="--layer: 1" title="2:Return: $DIR/spanview-statement.rs:5:13: 5:13:
-    5:13-5:13: Return: return"><span class="annotation">2:Return⦊</span>‸<span class="annotation">⦉2:Return</span></span></span></span></div>
+    5:11-5:13: Assign: _0 = const ()"><span class="annotation">0[0]⦊</span>{}<span class="annotation">⦉0[0]</span></span></span><span><span class="code odd" style="--layer: 1" title="0:Return: $DIR/spanview-statement.rs:5:13: 5:13:
+    5:13-5:13: Return: return"><span class="annotation">0:Return⦊</span>‸<span class="annotation">⦉0:Return</span></span></span></span></div>
 </body>
 </html>
diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir
deleted file mode 100644
index 072d224..0000000
--- a/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
-    .line {
-        counter-increment: line;
-    }
-    .line:before {
-        content: counter(line) ": ";
-        font-family: Menlo, Monaco, monospace;
-        font-style: italic;
-        width: 3.8em;
-        display: inline-block;
-        text-align: right;
-        filter: opacity(50%);
-        -webkit-user-select: none;
-    }
-    .code {
-        color: #dddddd;
-        background-color: #222222;
-        font-family: Menlo, Monaco, monospace;
-        line-height: 1.4em;
-        border-bottom: 2px solid #222222;
-        white-space: pre;
-        display: inline-block;
-    }
-    .odd {
-        background-color: #55bbff;
-        color: #223311;
-    }
-    .even {
-        background-color: #ee7756;
-        color: #551133;
-    }
-    .code {
-        --index: calc(var(--layer) - 1);
-        padding-top: calc(var(--index) * 0.15em);
-        filter:
-            hue-rotate(calc(var(--index) * 25deg))
-            saturate(calc(100% - (var(--index) * 2%)))
-            brightness(calc(100% - (var(--index) * 1.5%)));
-    }
-    .annotation {
-        color: #4444ff;
-        font-family: monospace;
-        font-style: italic;
-        display: none;
-        -webkit-user-select: none;
-    }
-    body:active .annotation {
-        /* requires holding mouse down anywhere on the page */
-        display: inline-block;
-    }
-    span:hover .annotation {
-        /* requires hover over a span ONLY on its first line */
-        display: inline-block;
-    }
-    </style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0[0]: $DIR/spanview-statement.rs:5:11: 5:13:
-    5:11-5:13: Assign: _0 = const ()"><span class="annotation">0[0]⦊</span>{}<span class="annotation">⦉0[0]</span></span></span><span><span class="code odd" style="--layer: 1" title="0:Goto: $DIR/spanview-statement.rs:5:13: 5:13:
-    5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">0:Goto⦊</span>‸<span class="annotation">⦉0:Goto</span></span></span><span><span class="code even" style="--layer: 1" title="2:Return: $DIR/spanview-statement.rs:5:13: 5:13:
-    5:13-5:13: Return: return"><span class="annotation">2:Return⦊</span>‸<span class="annotation">⦉2:Return</span></span></span></span></div>
-</body>
-</html>
diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html
index e023f0f..55fafd9 100644
--- a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html
+++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
+<title>spanview_terminator.main.mir_map.0</title>
+<style>
     .line {
         counter-increment: line;
     }
@@ -56,11 +56,10 @@
         /* requires hover over a span ONLY on its first line */
         display: inline-block;
     }
-    </style>
+</style>
 </head>
 <body>
-<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="0:Goto: $DIR/spanview-terminator.rs:5:13: 5:13:
-    5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">0:Goto⦊</span>‸<span class="annotation">⦉0:Goto</span></span></span><span><span class="code odd" style="--layer: 1" title="2:Return: $DIR/spanview-terminator.rs:5:13: 5:13:
-    5:13-5:13: Return: return"><span class="annotation">2:Return⦊</span>‸<span class="annotation">⦉2:Return</span></span></span></span></div>
+<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="0:Return: $DIR/spanview-terminator.rs:5:13: 5:13:
+    5:13-5:13: Return: return"><span class="annotation">0:Return⦊</span>‸<span class="annotation">⦉0:Return</span></span></span></span></div>
 </body>
 </html>
diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir
deleted file mode 100644
index e023f0f..0000000
--- a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir
+++ /dev/null
@@ -1,66 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
-    .line {
-        counter-increment: line;
-    }
-    .line:before {
-        content: counter(line) ": ";
-        font-family: Menlo, Monaco, monospace;
-        font-style: italic;
-        width: 3.8em;
-        display: inline-block;
-        text-align: right;
-        filter: opacity(50%);
-        -webkit-user-select: none;
-    }
-    .code {
-        color: #dddddd;
-        background-color: #222222;
-        font-family: Menlo, Monaco, monospace;
-        line-height: 1.4em;
-        border-bottom: 2px solid #222222;
-        white-space: pre;
-        display: inline-block;
-    }
-    .odd {
-        background-color: #55bbff;
-        color: #223311;
-    }
-    .even {
-        background-color: #ee7756;
-        color: #551133;
-    }
-    .code {
-        --index: calc(var(--layer) - 1);
-        padding-top: calc(var(--index) * 0.15em);
-        filter:
-            hue-rotate(calc(var(--index) * 25deg))
-            saturate(calc(100% - (var(--index) * 2%)))
-            brightness(calc(100% - (var(--index) * 1.5%)));
-    }
-    .annotation {
-        color: #4444ff;
-        font-family: monospace;
-        font-style: italic;
-        display: none;
-        -webkit-user-select: none;
-    }
-    body:active .annotation {
-        /* requires holding mouse down anywhere on the page */
-        display: inline-block;
-    }
-    span:hover .annotation {
-        /* requires hover over a span ONLY on its first line */
-        display: inline-block;
-    }
-    </style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="0:Goto: $DIR/spanview-terminator.rs:5:13: 5:13:
-    5:13-5:13: Goto: goto -&gt; bb2"><span class="annotation">0:Goto⦊</span>‸<span class="annotation">⦉0:Goto</span></span></span><span><span class="code odd" style="--layer: 1" title="2:Return: $DIR/spanview-terminator.rs:5:13: 5:13:
-    5:13-5:13: Return: return"><span class="annotation">2:Return⦊</span>‸<span class="annotation">⦉2:Return</span></span></span></span></div>
-</body>
-</html>
diff --git a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir
index 09ce2bd..6d05e82 100644
--- a/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir
+++ b/src/test/mir-opt/storage_live_dead_in_statics.XXX.mir_map.0.mir
@@ -159,8 +159,4 @@
         StorageDead(_1);                 // scope 0 at $DIR/storage_live_dead_in_statics.rs:23:1: 23:2
         return;                          // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:1: 23:3
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/storage_live_dead_in_statics.rs:5:1: 23:3
-    }
 }
diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
index dece3dc2..d18f630 100644
--- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
+++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
@@ -22,78 +22,62 @@
         _3 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
         (*_3) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
         _2 = move _3;                    // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-        drop(_3) -> [return: bb4, unwind: bb2]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+        drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2
-    }
-
-    bb2 (cleanup): {
-        drop(_2) -> bb1;                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
-    }
-
-    bb3 (cleanup): {
-        drop(_3) -> bb2;                 // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
-    }
-
-    bb4: {
+    bb1: {
         StorageDead(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
         StorageLive(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
         StorageLive(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
         _5 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
         (*_5) = const 2_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
         _4 = move _5;                    // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
-        drop(_5) -> [return: bb7, unwind: bb5]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+        drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
     }
 
-    bb5 (cleanup): {
-        drop(_4) -> bb2;                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
-    }
-
-    bb6 (cleanup): {
-        drop(_5) -> bb5;                 // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
-    }
-
-    bb7: {
+    bb2: {
         StorageDead(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
         _1 = [move _2, move _4];         // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27
-        drop(_4) -> [return: bb8, unwind: bb2]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+        drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
     }
 
-    bb8: {
+    bb3: {
         StorageDead(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
-        drop(_2) -> [return: bb9, unwind: bb1]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+        drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
     }
 
-    bb9: {
+    bb4: {
         StorageDead(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
         FakeRead(ForLet, _1);            // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
         StorageLive(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
         _6 = move _1[0..2];              // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
         _0 = const ();                   // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2
-        drop(_6) -> [return: bb12, unwind: bb10]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+        drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+    }
+
+    bb5: {
+        StorageDead(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+        drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+    }
+
+    bb6: {
+        StorageDead(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+        return;                          // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2
+    }
+
+    bb7 (cleanup): {
+        drop(_1) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+    }
+
+    bb8 (cleanup): {
+        drop(_4) -> bb9;                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+    }
+
+    bb9 (cleanup): {
+        drop(_2) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
     }
 
     bb10 (cleanup): {
-        drop(_1) -> bb1;                 // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
-    }
-
-    bb11 (cleanup): {
-        drop(_6) -> bb10;                // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
-    }
-
-    bb12: {
-        StorageDead(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
-        drop(_1) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
-    }
-
-    bb13: {
-        StorageDead(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
-        goto -> bb14;                    // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2
-    }
-
-    bb14: {
-        return;                          // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2
+        resume;                          // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2
     }
 }
diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir
index b182be5..eda8e5f 100644
--- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir
+++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir
@@ -22,78 +22,62 @@
         _3 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
         (*_3) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
         _2 = move _3;                    // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-        drop(_3) -> [return: bb4, unwind: bb2]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+        drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
     }
 
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2
-    }
-
-    bb2 (cleanup): {
-        drop(_2) -> bb1;                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
-    }
-
-    bb3 (cleanup): {
-        drop(_3) -> bb2;                 // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
-    }
-
-    bb4: {
+    bb1: {
         StorageDead(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
         StorageLive(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
         StorageLive(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
         _5 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
         (*_5) = const 2_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
         _4 = move _5;                    // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
-        drop(_5) -> [return: bb7, unwind: bb5]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+        drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
     }
 
-    bb5 (cleanup): {
-        drop(_4) -> bb2;                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
-    }
-
-    bb6 (cleanup): {
-        drop(_5) -> bb5;                 // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
-    }
-
-    bb7: {
+    bb2: {
         StorageDead(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
         _1 = [move _2, move _4];         // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27
-        drop(_4) -> [return: bb8, unwind: bb2]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+        drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
     }
 
-    bb8: {
+    bb3: {
         StorageDead(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
-        drop(_2) -> [return: bb9, unwind: bb1]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+        drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
     }
 
-    bb9: {
+    bb4: {
         StorageDead(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
         FakeRead(ForLet, _1);            // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
         StorageLive(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
         _6 = move _1[1 of 2];            // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
         _0 = const ();                   // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2
-        drop(_6) -> [return: bb12, unwind: bb10]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+        drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+    }
+
+    bb5: {
+        StorageDead(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+        drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+    }
+
+    bb6: {
+        StorageDead(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+        return;                          // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2
+    }
+
+    bb7 (cleanup): {
+        drop(_1) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+    }
+
+    bb8 (cleanup): {
+        drop(_4) -> bb9;                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+    }
+
+    bb9 (cleanup): {
+        drop(_2) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
     }
 
     bb10 (cleanup): {
-        drop(_1) -> bb1;                 // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
-    }
-
-    bb11 (cleanup): {
-        drop(_6) -> bb10;                // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
-    }
-
-    bb12: {
-        StorageDead(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
-        drop(_1) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
-    }
-
-    bb13: {
-        StorageDead(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
-        goto -> bb14;                    // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2
-    }
-
-    bb14: {
-        return;                          // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2
+        resume;                          // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2
     }
 }
diff --git "a/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.32bit.mir" "b/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.32bit.mir"
index f11fce8..7c7f03e 100644
--- "a/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.32bit.mir"
+++ "b/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.32bit.mir"
@@ -7,8 +7,4 @@
         _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
         return;                          // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
-    }
 }
diff --git "a/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.64bit.mir" "b/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.64bit.mir"
index f11fce8..7c7f03e 100644
--- "a/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.64bit.mir"
+++ "b/src/test/mir-opt/unusual_item_types.E-V-\173constant\0430\175.mir_map.0.64bit.mir"
@@ -7,8 +7,4 @@
         _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
         return;                          // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10
-    }
 }
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
index 2d96f64..e4af5b3 100644
--- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
@@ -6,7 +6,7 @@
     let mut _3: ();                      // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 
     bb0: {
-        goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
     }
 
     bb1: {
@@ -22,20 +22,16 @@
     }
 
     bb4 (cleanup): {
-        goto -> bb2;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
     }
 
-    bb5 (cleanup): {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+    bb5: {
+        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
     }
 
     bb6: {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-    }
-
-    bb7: {
         _2 = &mut (*_1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                          // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec<i32>) {<std::vec::Vec<i32> as std::ops::Drop>::drop}, val: Value(Scalar(<ZST>)) }
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
index 2d96f64..e4af5b3 100644
--- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
+++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
@@ -6,7 +6,7 @@
     let mut _3: ();                      // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 
     bb0: {
-        goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
     }
 
     bb1: {
@@ -22,20 +22,16 @@
     }
 
     bb4 (cleanup): {
-        goto -> bb2;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
     }
 
-    bb5 (cleanup): {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+    bb5: {
+        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
     }
 
     bb6: {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-    }
-
-    bb7: {
         _2 = &mut (*_1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                          // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec<i32>) {<std::vec::Vec<i32> as std::ops::Drop>::drop}, val: Value(Scalar(<ZST>)) }
diff --git "a/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir" "b/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir"
index fd3d707..a046a89 100644
--- "a/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir"
+++ "b/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir"
@@ -7,8 +7,4 @@
         _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
         return;                          // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:40
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:40
-    }
 }
diff --git "a/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir" "b/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir"
index fd3d707..a046a89 100644
--- "a/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir"
+++ "b/src/test/mir-opt/unusual_item_types.\173impl\0430\175-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir"
@@ -7,8 +7,4 @@
         _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:10:38: 10:39
         return;                          // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:40
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/unusual-item-types.rs:10:5: 10:40
-    }
 }
diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
index f4a7ffe..c27c68d 100644
--- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
+++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
@@ -52,7 +52,7 @@
     bb6: {
         _0 = const ();                   // scope 0 at $DIR/while-storage.rs:12:13: 12:18
         StorageDead(_4);                 // scope 0 at $DIR/while-storage.rs:14:5: 14:6
-        goto -> bb7;                     // scope 0 at $DIR/while-storage.rs:12:13: 12:18
+        goto -> bb7;                     // scope 0 at $DIR/while-storage.rs:1:1: 1:1
     }
 
     bb7: {
diff --git a/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile
new file mode 100644
index 0000000..e846429
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-llvmir-base/Makefile
@@ -0,0 +1,65 @@
+# needs-profiler-support
+
+# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
+# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
+# See ../coverage/coverage_tools.mk for more information.
+
+-include ../coverage/coverage_tools.mk
+
+BASEDIR=../coverage-llvmir-base
+
+ifeq ($(UNAME),Darwin)
+	INSTR_PROF_DATA_SUFFIX=,regular,live_support
+	DATA_SECTION_PREFIX=__DATA,
+	LLVM_COV_SECTION_PREFIX=__LLVM_COV,
+else
+	INSTR_PROF_DATA_SUFFIX=
+	DATA_SECTION_PREFIX=
+	LLVM_COV_SECTION_PREFIX=
+endif
+
+ifeq ($(LINK_DEAD_CODE),yes)
+	DEFINE_INTERNAL=define hidden
+else
+	DEFINE_INTERNAL=define internal
+endif
+
+ifdef IS_WINDOWS
+	LLVM_FILECHECK_OPTIONS=\
+		-check-prefixes=CHECK,WINDOWS \
+		-DPRIVATE_GLOBAL='internal global' \
+		-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
+		-DINSTR_PROF_DATA='.lprfd$$M' \
+		-DINSTR_PROF_NAME='.lprfn$$M' \
+		-DINSTR_PROF_CNTS='.lprfc$$M' \
+		-DINSTR_PROF_VALS='.lprfv$$M' \
+		-DINSTR_PROF_VNODES='.lprfnd$$M' \
+		-DINSTR_PROF_COVMAP='.lcovmap$$M' \
+		-DINSTR_PROF_ORDERFILE='.lorderfile$$M'
+else
+	LLVM_FILECHECK_OPTIONS=\
+		-check-prefixes=CHECK \
+		-DPRIVATE_GLOBAL='private global' \
+		-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
+		-DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \
+		-DINSTR_PROF_NAME='$(DATA_SECTION_PREFIX)__llvm_prf_names' \
+		-DINSTR_PROF_CNTS='$(DATA_SECTION_PREFIX)__llvm_prf_cnts' \
+		-DINSTR_PROF_VALS='$(DATA_SECTION_PREFIX)__llvm_prf_vals' \
+		-DINSTR_PROF_VNODES='$(DATA_SECTION_PREFIX)__llvm_prf_vnds' \
+		-DINSTR_PROF_COVMAP='$(LLVM_COV_SECTION_PREFIX)__llvm_covmap' \
+		-DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile'
+endif
+
+all:
+	# Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR
+	#
+	# Note: `-Clink-dead-code=no` disables the option, needed because the option is automatically
+	# enabled for some platforms, but not for Windows MSVC (due to Issue #76038). The state of this
+	# option affects the generated MIR and coverage, so it is enabled for tests to ensure the
+	# tests results are the same across platforms.
+	$(RUSTC) $(BASEDIR)/testprog.rs \
+			-Zinstrument-coverage \
+			-Clink-dead-code=$(LINK_DEAD_CODE) \
+			--emit=llvm-ir
+
+	cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS)
diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt b/src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt
similarity index 100%
rename from src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt
rename to src/test/run-make-fulldeps/coverage-llvmir-base/filecheck.testprog.txt
diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/testprog.rs b/src/test/run-make-fulldeps/coverage-llvmir-base/testprog.rs
similarity index 100%
rename from src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/testprog.rs
rename to src/test/run-make-fulldeps/coverage-llvmir-base/testprog.rs
diff --git a/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile
new file mode 100644
index 0000000..30c7c0f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-llvmir-deadcode/Makefile
@@ -0,0 +1,11 @@
+# needs-profiler-support
+# ignore-msvc
+
+# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038
+LINK_DEAD_CODE=yes
+
+-include ../coverage-llvmir-base/Makefile
+
+# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
+# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
+# See ../coverage/coverage_tools.mk for more information.
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/Makefile b/src/test/run-make-fulldeps/coverage-reports-base/Makefile
new file mode 100644
index 0000000..880d7fd
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/Makefile
@@ -0,0 +1,94 @@
+# needs-profiler-support
+# ignore-windows-gnu
+
+# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
+# properly. Since we only have GCC on the CI ignore the test for now.
+
+# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
+# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
+# See ../coverage/coverage_tools.mk for more information.
+
+-include ../coverage/coverage_tools.mk
+
+BASEDIR=../coverage-reports-base
+SOURCEDIR=../coverage
+
+all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
+
+# Ensure there are no `expected` results for tests that may have been removed or renamed
+.PHONY: clear_expected_if_blessed
+clear_expected_if_blessed:
+ifdef RUSTC_BLESS_TEST
+	rm -f expected_export_coverage.*.json
+	rm -f expected_show_coverage.*.txt
+endif
+
+-include clear_expected_if_blessed
+
+%: $(SOURCEDIR)/%.rs
+	# Compile the test program with coverage instrumentation and generate relevant MIR.
+	$(RUSTC) $(SOURCEDIR)/$@.rs \
+			-Zinstrument-coverage \
+			-Clink-dead-code=$(LINK_DEAD_CODE)
+
+	# Run it in order to generate some profiling data,
+	# with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
+	# output the coverage stats for this run.
+	LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \
+			$(call RUN,$@) || \
+			( \
+				status=$$?; \
+				grep -q "^\/\/ expect-exit-status-$$status" $(SOURCEDIR)/$@.rs || \
+				( >&2 echo "program exited with an unexpected exit status: $$status"; \
+					false \
+				) \
+			)
+
+	# Postprocess the profiling data so it can be used by the llvm-cov tool
+	"$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
+			"$(TMPDIR)"/$@.profraw \
+			-o "$(TMPDIR)"/$@.profdata
+
+	# Generate a coverage report using `llvm-cov show`. The output ordering
+	# can be non-deterministic, so ignore the return status. If the test fails
+	# when comparing the JSON `export`, the `show` output may be useful when
+	# debugging.
+	"$(LLVM_BIN_DIR)"/llvm-cov show \
+			--Xdemangler="$(RUST_DEMANGLER)" \
+			--show-line-counts-or-regions \
+			--instr-profile="$(TMPDIR)"/$@.profdata \
+			$(call BIN,"$(TMPDIR)"/$@) \
+		> "$(TMPDIR)"/actual_show_coverage.$@.txt
+
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/actual_show_coverage.$@.txt expected_show_coverage.$@.txt
+else
+	# Compare the show coverage output (`--bless` refreshes `typical` files)
+	# Note `llvm-cov show` output for some programs can vary, but can be ignored
+	# by inserting `// ignore-llvm-cov-show-diffs` at the top of the source file.
+
+	$(DIFF) expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \
+		( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \
+			>&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \
+		) || \
+		( >&2 echo 'diff failed, and not suppressed without `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs'; \
+			false \
+		)
+
+endif
+
+	# Generate a coverage report in JSON, using `llvm-cov export`, and fail if
+	# there are differences from the expected output.
+	"$(LLVM_BIN_DIR)"/llvm-cov export \
+			--summary-only \
+			--instr-profile="$(TMPDIR)"/$@.profdata \
+			$(call BIN,"$(TMPDIR)"/$@) \
+		| "$(PYTHON)" $(BASEDIR)/prettify_json.py \
+		> "$(TMPDIR)"/actual_export_coverage.$@.json
+
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json
+else
+	# Check that exported JSON coverage data matches what we expect (`--bless` refreshes `expected`)
+	$(DIFF) expected_export_coverage.$@.json "$(TMPDIR)"/actual_export_coverage.$@.json
+endif
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json
new file mode 100644
index 0000000..8c6edae
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.closure.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/closure.rs",
+          "summary": {
+            "functions": {
+              "count": 5,
+              "covered": 3,
+              "percent": 60
+            },
+            "instantiations": {
+              "count": 5,
+              "covered": 3,
+              "percent": 60
+            },
+            "lines": {
+              "count": 91,
+              "covered": 75,
+              "percent": 82.41758241758241
+            },
+            "regions": {
+              "count": 21,
+              "covered": 11,
+              "notcovered": 10,
+              "percent": 52.38095238095239
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 5,
+          "covered": 3,
+          "percent": 60
+        },
+        "instantiations": {
+          "count": 5,
+          "covered": 3,
+          "percent": 60
+        },
+        "lines": {
+          "count": 91,
+          "covered": 75,
+          "percent": 82.41758241758241
+        },
+        "regions": {
+          "count": 21,
+          "covered": 11,
+          "notcovered": 10,
+          "percent": 52.38095238095239
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json
new file mode 100644
index 0000000..bd2e2d5
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.drop_trait.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/drop_trait.rs",
+          "summary": {
+            "functions": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "lines": {
+              "count": 10,
+              "covered": 10,
+              "percent": 100
+            },
+            "regions": {
+              "count": 5,
+              "covered": 5,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "lines": {
+          "count": 10,
+          "covered": 10,
+          "percent": 100
+        },
+        "regions": {
+          "count": 5,
+          "covered": 5,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json
new file mode 100644
index 0000000..a50f465
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.generics.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/generics.rs",
+          "summary": {
+            "functions": {
+              "count": 3,
+              "covered": 3,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 5,
+              "covered": 5,
+              "percent": 100
+            },
+            "lines": {
+              "count": 16,
+              "covered": 16,
+              "percent": 100
+            },
+            "regions": {
+              "count": 6,
+              "covered": 6,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 3,
+          "covered": 3,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 5,
+          "covered": 5,
+          "percent": 100
+        },
+        "lines": {
+          "count": 16,
+          "covered": 16,
+          "percent": 100
+        },
+        "regions": {
+          "count": 6,
+          "covered": 6,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json
new file mode 100644
index 0000000..2ff53ad
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/if.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 19,
+              "covered": 19,
+              "percent": 100
+            },
+            "regions": {
+              "count": 4,
+              "covered": 4,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 19,
+          "covered": 19,
+          "percent": 100
+        },
+        "regions": {
+          "count": 4,
+          "covered": 4,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json
new file mode 100644
index 0000000..36f81ce
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.if_else.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/if_else.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 28,
+              "covered": 19,
+              "percent": 67.85714285714286
+            },
+            "regions": {
+              "count": 7,
+              "covered": 5,
+              "notcovered": 2,
+              "percent": 71.42857142857143
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 28,
+          "covered": 19,
+          "percent": 67.85714285714286
+        },
+        "regions": {
+          "count": 7,
+          "covered": 5,
+          "notcovered": 2,
+          "percent": 71.42857142857143
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json
new file mode 100644
index 0000000..a24e6a3
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.inner_items.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/inner_items.rs",
+          "summary": {
+            "functions": {
+              "count": 4,
+              "covered": 4,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 4,
+              "covered": 4,
+              "percent": 100
+            },
+            "lines": {
+              "count": 26,
+              "covered": 26,
+              "percent": 100
+            },
+            "regions": {
+              "count": 13,
+              "covered": 13,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 4,
+          "covered": 4,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 4,
+          "covered": 4,
+          "percent": 100
+        },
+        "lines": {
+          "count": 26,
+          "covered": 26,
+          "percent": 100
+        },
+        "regions": {
+          "count": 13,
+          "covered": 13,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json
new file mode 100644
index 0000000..585346d
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.lazy_boolean.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/lazy_boolean.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 21,
+              "covered": 19,
+              "percent": 90.47619047619048
+            },
+            "regions": {
+              "count": 16,
+              "covered": 14,
+              "notcovered": 2,
+              "percent": 87.5
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 21,
+          "covered": 19,
+          "percent": 90.47619047619048
+        },
+        "regions": {
+          "count": 16,
+          "covered": 14,
+          "notcovered": 2,
+          "percent": 87.5
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json
new file mode 100644
index 0000000..6cb1465c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.loop_break_value.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/loop_break_value.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 11,
+              "covered": 11,
+              "percent": 100
+            },
+            "regions": {
+              "count": 1,
+              "covered": 1,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 11,
+          "covered": 11,
+          "percent": 100
+        },
+        "regions": {
+          "count": 1,
+          "covered": 1,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json
new file mode 100644
index 0000000..38bc968
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_loop.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/simple_loop.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 18,
+              "covered": 18,
+              "percent": 100
+            },
+            "regions": {
+              "count": 7,
+              "covered": 7,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 18,
+          "covered": 18,
+          "percent": 100
+        },
+        "regions": {
+          "count": 7,
+          "covered": 7,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json
new file mode 100644
index 0000000..f9d91d6
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.simple_match.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/simple_match.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 26,
+              "covered": 26,
+              "percent": 100
+            },
+            "regions": {
+              "count": 9,
+              "covered": 9,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 26,
+          "covered": 26,
+          "percent": 100
+        },
+        "regions": {
+          "count": 9,
+          "covered": 9,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json
new file mode 100644
index 0000000..e6ef2c1
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.try_error_result.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/try_error_result.rs",
+          "summary": {
+            "functions": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "lines": {
+              "count": 16,
+              "covered": 15,
+              "percent": 93.75
+            },
+            "regions": {
+              "count": 13,
+              "covered": 12,
+              "notcovered": 1,
+              "percent": 92.3076923076923
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "lines": {
+          "count": 16,
+          "covered": 15,
+          "percent": 93.75
+        },
+        "regions": {
+          "count": 13,
+          "covered": 12,
+          "notcovered": 1,
+          "percent": 92.3076923076923
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.various_conditions.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.various_conditions.json
new file mode 100644
index 0000000..410821e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.various_conditions.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/various_conditions.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 49,
+              "covered": 23,
+              "percent": 46.93877551020408
+            },
+            "regions": {
+              "count": 51,
+              "covered": 19,
+              "notcovered": 32,
+              "percent": 37.254901960784316
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 49,
+          "covered": 23,
+          "percent": 46.93877551020408
+        },
+        "regions": {
+          "count": 51,
+          "covered": 19,
+          "notcovered": 32,
+          "percent": 37.254901960784316
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_return.json b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_return.json
new file mode 100644
index 0000000..865b705f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_export_coverage.while_early_return.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/while_early_return.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 18,
+              "covered": 16,
+              "percent": 88.88888888888889
+            },
+            "regions": {
+              "count": 9,
+              "covered": 7,
+              "notcovered": 2,
+              "percent": 77.77777777777779
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 18,
+          "covered": 16,
+          "percent": 88.88888888888889
+        },
+        "regions": {
+          "count": 9,
+          "covered": 7,
+          "notcovered": 2,
+          "percent": 77.77777777777779
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt
new file mode 100644
index 0000000..1705449
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.closure.txt
@@ -0,0 +1,94 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|      1|fn main() {
+    4|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|      1|    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|    let is_false = ! is_true;
+    9|      1|
+   10|      1|    let mut some_string = Some(String::from("the string content"));
+   11|      1|    println!(
+   12|      1|        "The string or alt: {}"
+   13|      1|        ,
+   14|      1|        some_string
+   15|      1|            .
+   16|      1|            unwrap_or_else
+   17|      1|        (
+   18|      1|            ||
+   19|       |            {
+   20|      0|                let mut countdown = 0;
+   21|      0|                if is_false {
+   22|      0|                    countdown = 10;
+   23|      0|                }
+   24|      0|                "alt string 1".to_owned()
+   25|      1|            }
+   26|      1|        )
+   27|      1|    );
+   28|      1|
+   29|      1|    some_string = Some(String::from("the string content"));
+   30|      1|    let
+   31|      1|        a
+   32|      1|    =
+   33|      1|        ||
+   34|       |    {
+   35|      0|        let mut countdown = 0;
+   36|      0|        if is_false {
+   37|      0|            countdown = 10;
+   38|      0|        }
+   39|      0|        "alt string 2".to_owned()
+   40|      1|    };
+   41|      1|    println!(
+   42|      1|        "The string or alt: {}"
+   43|      1|        ,
+   44|      1|        some_string
+   45|      1|            .
+   46|      1|            unwrap_or_else
+   47|      1|        (
+   48|      1|            a
+   49|      1|        )
+   50|      1|    );
+   51|      1|
+   52|      1|    some_string = None;
+   53|      1|    println!(
+   54|      1|        "The string or alt: {}"
+   55|      1|        ,
+   56|      1|        some_string
+   57|      1|            .
+   58|      1|            unwrap_or_else
+   59|      1|        (
+   60|      1|            ||
+   61|       |            {
+   62|      1|                let mut countdown = 0;
+   63|      1|                if is_false {
+   64|      0|                    countdown = 10;
+   65|      0|                }
+   66|      1|                "alt string 3".to_owned()
+   67|      1|            }
+   68|      1|        )
+   69|      1|    );
+   70|      1|
+   71|      1|    some_string = None;
+   72|      1|    let
+   73|      1|        a
+   74|      1|    =
+   75|      1|        ||
+   76|       |    {
+   77|      1|        let mut countdown = 0;
+   78|      1|        if is_false {
+   79|      0|            countdown = 10;
+   80|      0|        }
+   81|      1|        "alt string 4".to_owned()
+   82|      1|    };
+   83|      1|    println!(
+   84|      1|        "The string or alt: {}"
+   85|      1|        ,
+   86|      1|        some_string
+   87|      1|            .
+   88|      1|            unwrap_or_else
+   89|      1|        (
+   90|      1|            a
+   91|      1|        )
+   92|      1|    );
+   93|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt
new file mode 100644
index 0000000..72aa020
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.drop_trait.txt
@@ -0,0 +1,34 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |struct Firework {
+    5|       |    strength: i32,
+    6|       |}
+    7|       |
+    8|       |impl Drop for Firework {
+    9|      2|    fn drop(&mut self) {
+   10|      2|        println!("BOOM times {}!!!", self.strength);
+   11|      2|    }
+   12|       |}
+   13|       |
+   14|       |fn main() -> Result<(),u8> {
+   15|      1|    let _firecracker = Firework { strength: 1 };
+   16|      1|
+   17|      1|    let _tnt = Firework { strength: 100 };
+   18|       |
+   19|      1|    if true {
+   20|      1|        println!("Exiting with error...");
+   21|      1|        return Err(1);
+   22|       |    }
+   23|       |
+   24|       |    let _ = Firework { strength: 1000 };
+   25|       |
+   26|       |    Ok(())
+   27|      1|}
+   28|       |
+   29|       |// Expected program output:
+   30|       |//   Exiting with error...
+   31|       |//   BOOM times 100!!!
+   32|       |//   BOOM times 1!!!
+   33|       |//   Error: 1
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt
new file mode 100644
index 0000000..86199d7
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.generics.txt
@@ -0,0 +1,67 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |struct Firework<T> where T: Copy + std::fmt::Display {
+    5|       |    strength: T,
+    6|       |}
+    7|       |
+    8|       |impl<T> Firework<T> where T: Copy + std::fmt::Display {
+    9|       |    #[inline(always)]
+   10|      3|    fn set_strength(&mut self, new_strength: T) {
+   11|      3|        self.strength = new_strength;
+   12|      3|    }
+  ------------------
+  | <generics::Firework<f64>>::set_strength:
+  |   10|      2|    fn set_strength(&mut self, new_strength: T) {
+  |   11|      2|        self.strength = new_strength;
+  |   12|      2|    }
+  ------------------
+  | <generics::Firework<i32>>::set_strength:
+  |   10|      1|    fn set_strength(&mut self, new_strength: T) {
+  |   11|      1|        self.strength = new_strength;
+  |   12|      1|    }
+  ------------------
+   13|       |}
+   14|       |
+   15|       |impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display {
+   16|       |    #[inline(always)]
+   17|      2|    fn drop(&mut self) {
+   18|      2|        println!("BOOM times {}!!!", self.strength);
+   19|      2|    }
+  ------------------
+  | <generics::Firework<i32> as core::ops::drop::Drop>::drop:
+  |   17|      1|    fn drop(&mut self) {
+  |   18|      1|        println!("BOOM times {}!!!", self.strength);
+  |   19|      1|    }
+  ------------------
+  | <generics::Firework<f64> as core::ops::drop::Drop>::drop:
+  |   17|      1|    fn drop(&mut self) {
+  |   18|      1|        println!("BOOM times {}!!!", self.strength);
+  |   19|      1|    }
+  ------------------
+   20|       |}
+   21|       |
+   22|       |fn main() -> Result<(),u8> {
+   23|      1|    let mut firecracker = Firework { strength: 1 };
+   24|      1|    firecracker.set_strength(2);
+   25|      1|
+   26|      1|    let mut tnt = Firework { strength: 100.1 };
+   27|      1|    tnt.set_strength(200.1);
+   28|      1|    tnt.set_strength(300.3);
+   29|       |
+   30|      1|    if true {
+   31|      1|        println!("Exiting with error...");
+   32|      1|        return Err(1);
+   33|       |    }
+   34|       |
+   35|       |    let _ = Firework { strength: 1000 };
+   36|       |
+   37|       |    Ok(())
+   38|      1|}
+   39|       |
+   40|       |// Expected program output:
+   41|       |//   Exiting with error...
+   42|       |//   BOOM times 100!!!
+   43|       |//   BOOM times 1!!!
+   44|       |//   Error: 1
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt
new file mode 100644
index 0000000..bc2f9b1
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if.txt
@@ -0,0 +1,29 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|       |    let
+    8|      1|    is_true
+    9|      1|    =
+   10|      1|        std::env::args().len()
+   11|      1|    ==
+   12|      1|        1
+   13|      1|    ;
+   14|      1|    let
+   15|      1|        mut
+   16|      1|    countdown
+   17|      1|    =
+   18|      1|        0
+   19|       |    ;
+   20|       |    if
+   21|      1|        is_true
+   22|      1|    {
+   23|      1|        countdown
+   24|      1|        =
+   25|      1|            10
+   26|      1|        ;
+   27|      1|    }
+   28|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt
new file mode 100644
index 0000000..5f89972
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.if_else.txt
@@ -0,0 +1,41 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 0;
+   10|      1|    if
+   11|      1|        is_true
+   12|      1|    {
+   13|      1|        countdown
+   14|      1|        =
+   15|      1|            10
+   16|      1|        ;
+   17|      1|    }
+   18|       |    else // Note coverage region difference without semicolon
+   19|       |    {
+   20|      0|        countdown
+   21|      0|        =
+   22|      0|            100
+   23|       |    }
+   24|       |
+   25|       |    if
+   26|      1|        is_true
+   27|      1|    {
+   28|      1|        countdown
+   29|      1|        =
+   30|      1|            10
+   31|      1|        ;
+   32|      1|    }
+   33|       |    else
+   34|      0|    {
+   35|      0|        countdown
+   36|      0|        =
+   37|      0|            100
+   38|      0|        ;
+   39|      0|    }
+   40|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt
new file mode 100644
index 0000000..b13ca83
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.inner_items.txt
@@ -0,0 +1,58 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 0;
+   10|      1|    if is_true {
+   11|      1|        countdown = 10;
+   12|      1|    }
+   13|       |
+   14|       |    mod in_mod {
+   15|       |        const IN_MOD_CONST: u32 = 1000;
+   16|       |    }
+   17|       |
+   18|       |    fn in_func(a: u32) {
+   19|      3|        let b = 1;
+   20|      3|        let c = a + b;
+   21|      3|        println!("c = {}", c)
+   22|      3|    }
+   23|       |
+   24|       |    struct InStruct {
+   25|       |        in_struct_field: u32,
+   26|       |    }
+   27|       |
+   28|       |    const IN_CONST: u32 = 1234;
+   29|       |
+   30|       |    trait InTrait {
+   31|       |        fn trait_func(&mut self, incr: u32);
+   32|       |
+   33|      1|        fn default_trait_func(&mut self) {
+   34|      1|            in_func(IN_CONST);
+   35|      1|            self.trait_func(IN_CONST);
+   36|      1|        }
+   37|       |    }
+   38|       |
+   39|       |    impl InTrait for InStruct {
+   40|       |        fn trait_func(&mut self, incr: u32) {
+   41|      1|            self.in_struct_field += incr;
+   42|      1|            in_func(self.in_struct_field);
+   43|      1|        }
+   44|       |    }
+   45|       |
+   46|       |    type InType = String;
+   47|       |
+   48|      1|    if is_true {
+   49|      1|        in_func(countdown);
+   50|      1|    }
+   51|       |
+   52|      1|    let mut val = InStruct {
+   53|      1|        in_struct_field: 101,
+   54|      1|    };
+   55|      1|
+   56|      1|    val.default_trait_func();
+   57|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt
new file mode 100644
index 0000000..ded4369
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.lazy_boolean.txt
@@ -0,0 +1,44 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let (mut a, mut b, mut c) = (0, 0, 0);
+   10|      1|    if is_true {
+   11|      1|        a = 1;
+   12|      1|        b = 10;
+   13|      1|        c = 100;
+   14|      1|    }
+   15|       |    let
+   16|      1|        somebool
+   17|       |        =
+   18|      1|            a < b
+   19|       |        ||
+   20|      0|            b < c
+   21|       |    ;
+   22|       |    let
+   23|      1|        somebool
+   24|       |        =
+   25|      1|            b < a
+   26|       |        ||
+   27|      1|            b < c
+   28|       |    ;
+   29|       |    let
+   30|      1|        somebool
+   31|       |        =
+   32|      1|            a < b
+   33|       |        &&
+   34|      1|            b < c
+   35|       |    ;
+   36|       |    let
+   37|      1|        somebool
+   38|       |        =
+   39|      1|            b < a
+   40|       |        &&
+   41|      0|            b < c
+   42|       |    ;
+   43|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt
new file mode 100644
index 0000000..b0d668c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.loop_break_value.txt
@@ -0,0 +1,14 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|      1|fn main() {
+    4|      1|    let result
+    5|      1|        =
+    6|      1|            loop
+    7|      1|        {
+    8|      1|            break
+    9|      1|            10
+   10|      1|            ;
+   11|      1|        }
+   12|      1|    ;
+   13|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt
new file mode 100644
index 0000000..f1acb7c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_loop.txt
@@ -0,0 +1,36 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 0;
+   10|       |
+   11|       |    if
+   12|      1|        is_true
+   13|      1|    {
+   14|      1|        countdown
+   15|      1|        =
+   16|      1|            10
+   17|      1|        ;
+   18|      1|    }
+   19|       |
+   20|       |    loop
+   21|       |    {
+   22|       |        if
+   23|     11|            countdown
+   24|     11|                ==
+   25|     11|            0
+   26|       |        {
+   27|      1|            break
+   28|       |            ;
+   29|       |        }
+   30|     10|        countdown
+   31|     10|        -=
+   32|     10|        1
+   33|       |        ;
+   34|       |    }
+   35|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt
new file mode 100644
index 0000000..e42f22c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.simple_match.txt
@@ -0,0 +1,44 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 1;
+   10|      1|    if is_true {
+   11|      1|        countdown = 0;
+   12|      1|    }
+   13|       |
+   14|      3|    for
+   15|      3|        _
+   16|       |    in
+   17|      1|        0..2
+   18|       |    {
+   19|       |        let z
+   20|       |        ;
+   21|       |        match
+   22|      2|            countdown
+   23|      2|        {
+   24|      2|            x
+   25|      2|            if
+   26|      2|                x
+   27|      2|                    <
+   28|      2|                1
+   29|       |            =>
+   30|      1|            {
+   31|      1|                z = countdown
+   32|      1|                ;
+   33|      1|                let y = countdown
+   34|      1|                ;
+   35|      1|                countdown = 10
+   36|      1|                ;
+   37|      1|            }
+   38|       |            _
+   39|       |            =>
+   40|      1|            {}
+   41|       |        }
+   42|       |    }
+   43|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt
new file mode 100644
index 0000000..ae288d7
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.try_error_result.txt
@@ -0,0 +1,36 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |fn call(return_error: bool) -> Result<(),()> {
+    5|      6|    if return_error {
+    6|      1|        Err(())
+    7|       |    } else {
+    8|      5|        Ok(())
+    9|       |    }
+   10|      6|}
+   11|       |
+   12|       |fn main() -> Result<(),()> {
+   13|      1|    let mut
+   14|      1|        countdown = 10
+   15|       |    ;
+   16|      6|    for
+   17|      6|        _
+   18|       |    in
+   19|      1|        0..10
+   20|       |    {
+   21|      6|        countdown
+   22|      6|            -= 1
+   23|       |        ;
+   24|       |        if
+   25|      6|            countdown < 5
+   26|       |        {
+   27|      1|            call(/*return_error=*/ true)?;
+   28|       |        }
+   29|       |        else
+   30|       |        {
+   31|      5|            call(/*return_error=*/ false)?;
+   32|       |        }
+   33|       |    }
+   34|      0|    Ok(())
+   35|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.various_conditions.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.various_conditions.txt
new file mode 100644
index 0000000..173ff4a
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.various_conditions.txt
@@ -0,0 +1,69 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|      1|    let mut countdown = 0;
+    5|      1|    if true {
+    6|      1|        countdown = 10;
+    7|      1|    }
+    8|       |
+    9|       |    const B: u32 = 100;
+   10|      1|    let x = if countdown > 7 {
+   11|      1|        countdown -= 4;
+   12|      1|        B
+   13|      0|    } else if countdown > 2 {
+   14|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   15|      0|            countdown = 0;
+   16|      0|        }
+   17|      0|        countdown -= 5;
+   18|      0|        countdown
+   19|       |    } else {
+   20|      0|        return;
+   21|       |    };
+   22|       |
+   23|      1|    let mut countdown = 0;
+   24|      1|    if true {
+   25|      1|        countdown = 10;
+   26|      1|    }
+   27|       |
+   28|      1|    if countdown > 7 {
+   29|      1|        countdown -= 4;
+   30|      0|    } else if countdown > 2 {
+   31|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   32|      0|            countdown = 0;
+   33|      0|        }
+   34|      0|        countdown -= 5;
+   35|       |    } else {
+   36|      0|        return;
+   37|       |    }
+   38|       |
+   39|      1|    let mut countdown = 0;
+   40|      1|    if true {
+   41|      1|        countdown = 1;
+   42|      1|    }
+   43|       |
+   44|      1|    let z = if countdown > 7 {
+                      ^0
+   45|      0|        countdown -= 4;
+   46|      1|    } else if countdown > 2 {
+   47|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   48|      0|            countdown = 0;
+   49|      0|        }
+   50|      0|        countdown -= 5;
+   51|       |    } else {
+   52|      1|        let should_be_reachable = countdown;
+   53|      1|        println!("reached");
+   54|      1|        return;
+   55|       |    };
+   56|       |
+   57|      0|    let w = if countdown > 7 {
+   58|      0|        countdown -= 4;
+   59|      0|    } else if countdown > 2 {
+   60|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   61|      0|            countdown = 0;
+   62|      0|        }
+   63|      0|        countdown -= 5;
+   64|       |    } else {
+   65|      0|        return;
+   66|       |    };
+   67|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_return.txt b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_return.txt
new file mode 100644
index 0000000..7dce94f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-base/expected_show_coverage.while_early_return.txt
@@ -0,0 +1,48 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |fn main() -> Result<(),u8> {
+    5|      1|    let mut countdown = 10;
+    6|      7|    while
+    7|      7|        countdown
+    8|      7|            >
+    9|      7|        0
+   10|       |    {
+   11|       |        if
+   12|      7|            countdown
+   13|      7|                <
+   14|      7|            5
+   15|       |        {
+   16|       |            return
+   17|       |                if
+   18|      1|                    countdown
+   19|      1|                        >
+   20|      1|                    8
+   21|       |                {
+   22|      0|                    Ok(())
+   23|       |                }
+   24|       |                else
+   25|       |                {
+   26|      1|                    Err(1)
+   27|       |                }
+   28|       |                ;
+   29|       |        }
+   30|      6|        countdown
+   31|      6|            -=
+   32|      6|        1
+   33|       |        ;
+   34|       |    }
+   35|      0|    Ok(())
+   36|      1|}
+   37|       |
+   38|       |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and
+   39|       |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux
+   40|       |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program
+   41|       |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical
+   42|       |// to the coverage test for early returns, but this is a limitation that should be fixed.
+   43|       |//
+   44|       |// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`,
+   45|       |// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping
+   46|       |// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the
+   47|       |// problem exists on MSVC only).
+
diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/prettify_json.py b/src/test/run-make-fulldeps/coverage-reports-base/prettify_json.py
similarity index 100%
rename from src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/prettify_json.py
rename to src/test/run-make-fulldeps/coverage-reports-base/prettify_json.py
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile
new file mode 100644
index 0000000..b6a9acb
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/Makefile
@@ -0,0 +1,15 @@
+# needs-profiler-support
+# ignore-msvc
+# ignore-windows-gnu
+
+# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
+# properly. Since we only have GCC on the CI ignore the test for now.
+
+# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038
+LINK_DEAD_CODE=yes
+
+-include ../coverage-reports-base/Makefile
+
+# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
+# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
+# See ../coverage/coverage_tools.mk for more information.
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.closure.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.closure.json
new file mode 100644
index 0000000..8c6edae
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.closure.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/closure.rs",
+          "summary": {
+            "functions": {
+              "count": 5,
+              "covered": 3,
+              "percent": 60
+            },
+            "instantiations": {
+              "count": 5,
+              "covered": 3,
+              "percent": 60
+            },
+            "lines": {
+              "count": 91,
+              "covered": 75,
+              "percent": 82.41758241758241
+            },
+            "regions": {
+              "count": 21,
+              "covered": 11,
+              "notcovered": 10,
+              "percent": 52.38095238095239
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 5,
+          "covered": 3,
+          "percent": 60
+        },
+        "instantiations": {
+          "count": 5,
+          "covered": 3,
+          "percent": 60
+        },
+        "lines": {
+          "count": 91,
+          "covered": 75,
+          "percent": 82.41758241758241
+        },
+        "regions": {
+          "count": 21,
+          "covered": 11,
+          "notcovered": 10,
+          "percent": 52.38095238095239
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.drop_trait.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.drop_trait.json
new file mode 100644
index 0000000..bd2e2d5
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.drop_trait.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/drop_trait.rs",
+          "summary": {
+            "functions": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "lines": {
+              "count": 10,
+              "covered": 10,
+              "percent": 100
+            },
+            "regions": {
+              "count": 5,
+              "covered": 5,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "lines": {
+          "count": 10,
+          "covered": 10,
+          "percent": 100
+        },
+        "regions": {
+          "count": 5,
+          "covered": 5,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.generics.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.generics.json
new file mode 100644
index 0000000..a50f465
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.generics.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/generics.rs",
+          "summary": {
+            "functions": {
+              "count": 3,
+              "covered": 3,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 5,
+              "covered": 5,
+              "percent": 100
+            },
+            "lines": {
+              "count": 16,
+              "covered": 16,
+              "percent": 100
+            },
+            "regions": {
+              "count": 6,
+              "covered": 6,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 3,
+          "covered": 3,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 5,
+          "covered": 5,
+          "percent": 100
+        },
+        "lines": {
+          "count": 16,
+          "covered": 16,
+          "percent": 100
+        },
+        "regions": {
+          "count": 6,
+          "covered": 6,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if.json
new file mode 100644
index 0000000..2ff53ad
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/if.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 19,
+              "covered": 19,
+              "percent": 100
+            },
+            "regions": {
+              "count": 4,
+              "covered": 4,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 19,
+          "covered": 19,
+          "percent": 100
+        },
+        "regions": {
+          "count": 4,
+          "covered": 4,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if_else.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if_else.json
new file mode 100644
index 0000000..36f81ce
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.if_else.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/if_else.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 28,
+              "covered": 19,
+              "percent": 67.85714285714286
+            },
+            "regions": {
+              "count": 7,
+              "covered": 5,
+              "notcovered": 2,
+              "percent": 71.42857142857143
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 28,
+          "covered": 19,
+          "percent": 67.85714285714286
+        },
+        "regions": {
+          "count": 7,
+          "covered": 5,
+          "notcovered": 2,
+          "percent": 71.42857142857143
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json
new file mode 100644
index 0000000..a24e6a3
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.inner_items.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/inner_items.rs",
+          "summary": {
+            "functions": {
+              "count": 4,
+              "covered": 4,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 4,
+              "covered": 4,
+              "percent": 100
+            },
+            "lines": {
+              "count": 26,
+              "covered": 26,
+              "percent": 100
+            },
+            "regions": {
+              "count": 13,
+              "covered": 13,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 4,
+          "covered": 4,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 4,
+          "covered": 4,
+          "percent": 100
+        },
+        "lines": {
+          "count": 26,
+          "covered": 26,
+          "percent": 100
+        },
+        "regions": {
+          "count": 13,
+          "covered": 13,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.lazy_boolean.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.lazy_boolean.json
new file mode 100644
index 0000000..585346d
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.lazy_boolean.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/lazy_boolean.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 21,
+              "covered": 19,
+              "percent": 90.47619047619048
+            },
+            "regions": {
+              "count": 16,
+              "covered": 14,
+              "notcovered": 2,
+              "percent": 87.5
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 21,
+          "covered": 19,
+          "percent": 90.47619047619048
+        },
+        "regions": {
+          "count": 16,
+          "covered": 14,
+          "notcovered": 2,
+          "percent": 87.5
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loop_break_value.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loop_break_value.json
new file mode 100644
index 0000000..6cb1465c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.loop_break_value.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/loop_break_value.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 11,
+              "covered": 11,
+              "percent": 100
+            },
+            "regions": {
+              "count": 1,
+              "covered": 1,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 11,
+          "covered": 11,
+          "percent": 100
+        },
+        "regions": {
+          "count": 1,
+          "covered": 1,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_loop.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_loop.json
new file mode 100644
index 0000000..38bc968
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_loop.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/simple_loop.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 18,
+              "covered": 18,
+              "percent": 100
+            },
+            "regions": {
+              "count": 7,
+              "covered": 7,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 18,
+          "covered": 18,
+          "percent": 100
+        },
+        "regions": {
+          "count": 7,
+          "covered": 7,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_match.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_match.json
new file mode 100644
index 0000000..f9d91d6
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.simple_match.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/simple_match.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 26,
+              "covered": 26,
+              "percent": 100
+            },
+            "regions": {
+              "count": 9,
+              "covered": 9,
+              "notcovered": 0,
+              "percent": 100
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 26,
+          "covered": 26,
+          "percent": 100
+        },
+        "regions": {
+          "count": 9,
+          "covered": 9,
+          "notcovered": 0,
+          "percent": 100
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.try_error_result.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.try_error_result.json
new file mode 100644
index 0000000..e6ef2c1
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.try_error_result.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/try_error_result.rs",
+          "summary": {
+            "functions": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 2,
+              "covered": 2,
+              "percent": 100
+            },
+            "lines": {
+              "count": 16,
+              "covered": 15,
+              "percent": 93.75
+            },
+            "regions": {
+              "count": 13,
+              "covered": 12,
+              "notcovered": 1,
+              "percent": 92.3076923076923
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 2,
+          "covered": 2,
+          "percent": 100
+        },
+        "lines": {
+          "count": 16,
+          "covered": 15,
+          "percent": 93.75
+        },
+        "regions": {
+          "count": 13,
+          "covered": 12,
+          "notcovered": 1,
+          "percent": 92.3076923076923
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.various_conditions.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.various_conditions.json
new file mode 100644
index 0000000..410821e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.various_conditions.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/various_conditions.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 49,
+              "covered": 23,
+              "percent": 46.93877551020408
+            },
+            "regions": {
+              "count": 51,
+              "covered": 19,
+              "notcovered": 32,
+              "percent": 37.254901960784316
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 49,
+          "covered": 23,
+          "percent": 46.93877551020408
+        },
+        "regions": {
+          "count": 51,
+          "covered": 19,
+          "notcovered": 32,
+          "percent": 37.254901960784316
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while_early_return.json b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while_early_return.json
new file mode 100644
index 0000000..865b705f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_export_coverage.while_early_return.json
@@ -0,0 +1,59 @@
+{
+  "data": [
+    {
+      "files": [
+        {
+          "filename": "../coverage/while_early_return.rs",
+          "summary": {
+            "functions": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "instantiations": {
+              "count": 1,
+              "covered": 1,
+              "percent": 100
+            },
+            "lines": {
+              "count": 18,
+              "covered": 16,
+              "percent": 88.88888888888889
+            },
+            "regions": {
+              "count": 9,
+              "covered": 7,
+              "notcovered": 2,
+              "percent": 77.77777777777779
+            }
+          }
+        }
+      ],
+      "totals": {
+        "functions": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "instantiations": {
+          "count": 1,
+          "covered": 1,
+          "percent": 100
+        },
+        "lines": {
+          "count": 18,
+          "covered": 16,
+          "percent": 88.88888888888889
+        },
+        "regions": {
+          "count": 9,
+          "covered": 7,
+          "notcovered": 2,
+          "percent": 77.77777777777779
+        }
+      }
+    }
+  ],
+  "type": "llvm.coverage.json.export",
+  "version": "2.0.1"
+}
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.closure.txt
new file mode 100644
index 0000000..1705449
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.closure.txt
@@ -0,0 +1,94 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|      1|fn main() {
+    4|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|      1|    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|    let is_false = ! is_true;
+    9|      1|
+   10|      1|    let mut some_string = Some(String::from("the string content"));
+   11|      1|    println!(
+   12|      1|        "The string or alt: {}"
+   13|      1|        ,
+   14|      1|        some_string
+   15|      1|            .
+   16|      1|            unwrap_or_else
+   17|      1|        (
+   18|      1|            ||
+   19|       |            {
+   20|      0|                let mut countdown = 0;
+   21|      0|                if is_false {
+   22|      0|                    countdown = 10;
+   23|      0|                }
+   24|      0|                "alt string 1".to_owned()
+   25|      1|            }
+   26|      1|        )
+   27|      1|    );
+   28|      1|
+   29|      1|    some_string = Some(String::from("the string content"));
+   30|      1|    let
+   31|      1|        a
+   32|      1|    =
+   33|      1|        ||
+   34|       |    {
+   35|      0|        let mut countdown = 0;
+   36|      0|        if is_false {
+   37|      0|            countdown = 10;
+   38|      0|        }
+   39|      0|        "alt string 2".to_owned()
+   40|      1|    };
+   41|      1|    println!(
+   42|      1|        "The string or alt: {}"
+   43|      1|        ,
+   44|      1|        some_string
+   45|      1|            .
+   46|      1|            unwrap_or_else
+   47|      1|        (
+   48|      1|            a
+   49|      1|        )
+   50|      1|    );
+   51|      1|
+   52|      1|    some_string = None;
+   53|      1|    println!(
+   54|      1|        "The string or alt: {}"
+   55|      1|        ,
+   56|      1|        some_string
+   57|      1|            .
+   58|      1|            unwrap_or_else
+   59|      1|        (
+   60|      1|            ||
+   61|       |            {
+   62|      1|                let mut countdown = 0;
+   63|      1|                if is_false {
+   64|      0|                    countdown = 10;
+   65|      0|                }
+   66|      1|                "alt string 3".to_owned()
+   67|      1|            }
+   68|      1|        )
+   69|      1|    );
+   70|      1|
+   71|      1|    some_string = None;
+   72|      1|    let
+   73|      1|        a
+   74|      1|    =
+   75|      1|        ||
+   76|       |    {
+   77|      1|        let mut countdown = 0;
+   78|      1|        if is_false {
+   79|      0|            countdown = 10;
+   80|      0|        }
+   81|      1|        "alt string 4".to_owned()
+   82|      1|    };
+   83|      1|    println!(
+   84|      1|        "The string or alt: {}"
+   85|      1|        ,
+   86|      1|        some_string
+   87|      1|            .
+   88|      1|            unwrap_or_else
+   89|      1|        (
+   90|      1|            a
+   91|      1|        )
+   92|      1|    );
+   93|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.drop_trait.txt
new file mode 100644
index 0000000..72aa020
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.drop_trait.txt
@@ -0,0 +1,34 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |struct Firework {
+    5|       |    strength: i32,
+    6|       |}
+    7|       |
+    8|       |impl Drop for Firework {
+    9|      2|    fn drop(&mut self) {
+   10|      2|        println!("BOOM times {}!!!", self.strength);
+   11|      2|    }
+   12|       |}
+   13|       |
+   14|       |fn main() -> Result<(),u8> {
+   15|      1|    let _firecracker = Firework { strength: 1 };
+   16|      1|
+   17|      1|    let _tnt = Firework { strength: 100 };
+   18|       |
+   19|      1|    if true {
+   20|      1|        println!("Exiting with error...");
+   21|      1|        return Err(1);
+   22|       |    }
+   23|       |
+   24|       |    let _ = Firework { strength: 1000 };
+   25|       |
+   26|       |    Ok(())
+   27|      1|}
+   28|       |
+   29|       |// Expected program output:
+   30|       |//   Exiting with error...
+   31|       |//   BOOM times 100!!!
+   32|       |//   BOOM times 1!!!
+   33|       |//   Error: 1
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.generics.txt
new file mode 100644
index 0000000..86199d7
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.generics.txt
@@ -0,0 +1,67 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |struct Firework<T> where T: Copy + std::fmt::Display {
+    5|       |    strength: T,
+    6|       |}
+    7|       |
+    8|       |impl<T> Firework<T> where T: Copy + std::fmt::Display {
+    9|       |    #[inline(always)]
+   10|      3|    fn set_strength(&mut self, new_strength: T) {
+   11|      3|        self.strength = new_strength;
+   12|      3|    }
+  ------------------
+  | <generics::Firework<f64>>::set_strength:
+  |   10|      2|    fn set_strength(&mut self, new_strength: T) {
+  |   11|      2|        self.strength = new_strength;
+  |   12|      2|    }
+  ------------------
+  | <generics::Firework<i32>>::set_strength:
+  |   10|      1|    fn set_strength(&mut self, new_strength: T) {
+  |   11|      1|        self.strength = new_strength;
+  |   12|      1|    }
+  ------------------
+   13|       |}
+   14|       |
+   15|       |impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display {
+   16|       |    #[inline(always)]
+   17|      2|    fn drop(&mut self) {
+   18|      2|        println!("BOOM times {}!!!", self.strength);
+   19|      2|    }
+  ------------------
+  | <generics::Firework<i32> as core::ops::drop::Drop>::drop:
+  |   17|      1|    fn drop(&mut self) {
+  |   18|      1|        println!("BOOM times {}!!!", self.strength);
+  |   19|      1|    }
+  ------------------
+  | <generics::Firework<f64> as core::ops::drop::Drop>::drop:
+  |   17|      1|    fn drop(&mut self) {
+  |   18|      1|        println!("BOOM times {}!!!", self.strength);
+  |   19|      1|    }
+  ------------------
+   20|       |}
+   21|       |
+   22|       |fn main() -> Result<(),u8> {
+   23|      1|    let mut firecracker = Firework { strength: 1 };
+   24|      1|    firecracker.set_strength(2);
+   25|      1|
+   26|      1|    let mut tnt = Firework { strength: 100.1 };
+   27|      1|    tnt.set_strength(200.1);
+   28|      1|    tnt.set_strength(300.3);
+   29|       |
+   30|      1|    if true {
+   31|      1|        println!("Exiting with error...");
+   32|      1|        return Err(1);
+   33|       |    }
+   34|       |
+   35|       |    let _ = Firework { strength: 1000 };
+   36|       |
+   37|       |    Ok(())
+   38|      1|}
+   39|       |
+   40|       |// Expected program output:
+   41|       |//   Exiting with error...
+   42|       |//   BOOM times 100!!!
+   43|       |//   BOOM times 1!!!
+   44|       |//   Error: 1
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if.txt
new file mode 100644
index 0000000..bc2f9b1
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if.txt
@@ -0,0 +1,29 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|       |    let
+    8|      1|    is_true
+    9|      1|    =
+   10|      1|        std::env::args().len()
+   11|      1|    ==
+   12|      1|        1
+   13|      1|    ;
+   14|      1|    let
+   15|      1|        mut
+   16|      1|    countdown
+   17|      1|    =
+   18|      1|        0
+   19|       |    ;
+   20|       |    if
+   21|      1|        is_true
+   22|      1|    {
+   23|      1|        countdown
+   24|      1|        =
+   25|      1|            10
+   26|      1|        ;
+   27|      1|    }
+   28|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if_else.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if_else.txt
new file mode 100644
index 0000000..5f89972
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.if_else.txt
@@ -0,0 +1,41 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 0;
+   10|      1|    if
+   11|      1|        is_true
+   12|      1|    {
+   13|      1|        countdown
+   14|      1|        =
+   15|      1|            10
+   16|      1|        ;
+   17|      1|    }
+   18|       |    else // Note coverage region difference without semicolon
+   19|       |    {
+   20|      0|        countdown
+   21|      0|        =
+   22|      0|            100
+   23|       |    }
+   24|       |
+   25|       |    if
+   26|      1|        is_true
+   27|      1|    {
+   28|      1|        countdown
+   29|      1|        =
+   30|      1|            10
+   31|      1|        ;
+   32|      1|    }
+   33|       |    else
+   34|      0|    {
+   35|      0|        countdown
+   36|      0|        =
+   37|      0|            100
+   38|      0|        ;
+   39|      0|    }
+   40|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt
new file mode 100644
index 0000000..b13ca83
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.inner_items.txt
@@ -0,0 +1,58 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 0;
+   10|      1|    if is_true {
+   11|      1|        countdown = 10;
+   12|      1|    }
+   13|       |
+   14|       |    mod in_mod {
+   15|       |        const IN_MOD_CONST: u32 = 1000;
+   16|       |    }
+   17|       |
+   18|       |    fn in_func(a: u32) {
+   19|      3|        let b = 1;
+   20|      3|        let c = a + b;
+   21|      3|        println!("c = {}", c)
+   22|      3|    }
+   23|       |
+   24|       |    struct InStruct {
+   25|       |        in_struct_field: u32,
+   26|       |    }
+   27|       |
+   28|       |    const IN_CONST: u32 = 1234;
+   29|       |
+   30|       |    trait InTrait {
+   31|       |        fn trait_func(&mut self, incr: u32);
+   32|       |
+   33|      1|        fn default_trait_func(&mut self) {
+   34|      1|            in_func(IN_CONST);
+   35|      1|            self.trait_func(IN_CONST);
+   36|      1|        }
+   37|       |    }
+   38|       |
+   39|       |    impl InTrait for InStruct {
+   40|       |        fn trait_func(&mut self, incr: u32) {
+   41|      1|            self.in_struct_field += incr;
+   42|      1|            in_func(self.in_struct_field);
+   43|      1|        }
+   44|       |    }
+   45|       |
+   46|       |    type InType = String;
+   47|       |
+   48|      1|    if is_true {
+   49|      1|        in_func(countdown);
+   50|      1|    }
+   51|       |
+   52|      1|    let mut val = InStruct {
+   53|      1|        in_struct_field: 101,
+   54|      1|    };
+   55|      1|
+   56|      1|    val.default_trait_func();
+   57|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.lazy_boolean.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.lazy_boolean.txt
new file mode 100644
index 0000000..ded4369
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.lazy_boolean.txt
@@ -0,0 +1,44 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let (mut a, mut b, mut c) = (0, 0, 0);
+   10|      1|    if is_true {
+   11|      1|        a = 1;
+   12|      1|        b = 10;
+   13|      1|        c = 100;
+   14|      1|    }
+   15|       |    let
+   16|      1|        somebool
+   17|       |        =
+   18|      1|            a < b
+   19|       |        ||
+   20|      0|            b < c
+   21|       |    ;
+   22|       |    let
+   23|      1|        somebool
+   24|       |        =
+   25|      1|            b < a
+   26|       |        ||
+   27|      1|            b < c
+   28|       |    ;
+   29|       |    let
+   30|      1|        somebool
+   31|       |        =
+   32|      1|            a < b
+   33|       |        &&
+   34|      1|            b < c
+   35|       |    ;
+   36|       |    let
+   37|      1|        somebool
+   38|       |        =
+   39|      1|            b < a
+   40|       |        &&
+   41|      0|            b < c
+   42|       |    ;
+   43|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loop_break_value.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loop_break_value.txt
new file mode 100644
index 0000000..b0d668c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.loop_break_value.txt
@@ -0,0 +1,14 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|      1|fn main() {
+    4|      1|    let result
+    5|      1|        =
+    6|      1|            loop
+    7|      1|        {
+    8|      1|            break
+    9|      1|            10
+   10|      1|            ;
+   11|      1|        }
+   12|      1|    ;
+   13|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_loop.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_loop.txt
new file mode 100644
index 0000000..f1acb7c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_loop.txt
@@ -0,0 +1,36 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 0;
+   10|       |
+   11|       |    if
+   12|      1|        is_true
+   13|      1|    {
+   14|      1|        countdown
+   15|      1|        =
+   16|      1|            10
+   17|      1|        ;
+   18|      1|    }
+   19|       |
+   20|       |    loop
+   21|       |    {
+   22|       |        if
+   23|     11|            countdown
+   24|     11|                ==
+   25|     11|            0
+   26|       |        {
+   27|      1|            break
+   28|       |            ;
+   29|       |        }
+   30|     10|        countdown
+   31|     10|        -=
+   32|     10|        1
+   33|       |        ;
+   34|       |    }
+   35|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_match.txt
new file mode 100644
index 0000000..e42f22c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.simple_match.txt
@@ -0,0 +1,44 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |
+    3|       |fn main() {
+    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|       |    // dependent conditions.
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|
+    9|      1|    let mut countdown = 1;
+   10|      1|    if is_true {
+   11|      1|        countdown = 0;
+   12|      1|    }
+   13|       |
+   14|      3|    for
+   15|      3|        _
+   16|       |    in
+   17|      1|        0..2
+   18|       |    {
+   19|       |        let z
+   20|       |        ;
+   21|       |        match
+   22|      2|            countdown
+   23|      2|        {
+   24|      2|            x
+   25|      2|            if
+   26|      2|                x
+   27|      2|                    <
+   28|      2|                1
+   29|       |            =>
+   30|      1|            {
+   31|      1|                z = countdown
+   32|      1|                ;
+   33|      1|                let y = countdown
+   34|      1|                ;
+   35|      1|                countdown = 10
+   36|      1|                ;
+   37|      1|            }
+   38|       |            _
+   39|       |            =>
+   40|      1|            {}
+   41|       |        }
+   42|       |    }
+   43|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.try_error_result.txt
new file mode 100644
index 0000000..ae288d7
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.try_error_result.txt
@@ -0,0 +1,36 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |fn call(return_error: bool) -> Result<(),()> {
+    5|      6|    if return_error {
+    6|      1|        Err(())
+    7|       |    } else {
+    8|      5|        Ok(())
+    9|       |    }
+   10|      6|}
+   11|       |
+   12|       |fn main() -> Result<(),()> {
+   13|      1|    let mut
+   14|      1|        countdown = 10
+   15|       |    ;
+   16|      6|    for
+   17|      6|        _
+   18|       |    in
+   19|      1|        0..10
+   20|       |    {
+   21|      6|        countdown
+   22|      6|            -= 1
+   23|       |        ;
+   24|       |        if
+   25|      6|            countdown < 5
+   26|       |        {
+   27|      1|            call(/*return_error=*/ true)?;
+   28|       |        }
+   29|       |        else
+   30|       |        {
+   31|      5|            call(/*return_error=*/ false)?;
+   32|       |        }
+   33|       |    }
+   34|      0|    Ok(())
+   35|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.various_conditions.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.various_conditions.txt
new file mode 100644
index 0000000..173ff4a
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.various_conditions.txt
@@ -0,0 +1,69 @@
+    1|       |#![allow(unused_assignments, unused_variables)]
+    2|       |
+    3|       |fn main() {
+    4|      1|    let mut countdown = 0;
+    5|      1|    if true {
+    6|      1|        countdown = 10;
+    7|      1|    }
+    8|       |
+    9|       |    const B: u32 = 100;
+   10|      1|    let x = if countdown > 7 {
+   11|      1|        countdown -= 4;
+   12|      1|        B
+   13|      0|    } else if countdown > 2 {
+   14|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   15|      0|            countdown = 0;
+   16|      0|        }
+   17|      0|        countdown -= 5;
+   18|      0|        countdown
+   19|       |    } else {
+   20|      0|        return;
+   21|       |    };
+   22|       |
+   23|      1|    let mut countdown = 0;
+   24|      1|    if true {
+   25|      1|        countdown = 10;
+   26|      1|    }
+   27|       |
+   28|      1|    if countdown > 7 {
+   29|      1|        countdown -= 4;
+   30|      0|    } else if countdown > 2 {
+   31|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   32|      0|            countdown = 0;
+   33|      0|        }
+   34|      0|        countdown -= 5;
+   35|       |    } else {
+   36|      0|        return;
+   37|       |    }
+   38|       |
+   39|      1|    let mut countdown = 0;
+   40|      1|    if true {
+   41|      1|        countdown = 1;
+   42|      1|    }
+   43|       |
+   44|      1|    let z = if countdown > 7 {
+                      ^0
+   45|      0|        countdown -= 4;
+   46|      1|    } else if countdown > 2 {
+   47|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   48|      0|            countdown = 0;
+   49|      0|        }
+   50|      0|        countdown -= 5;
+   51|       |    } else {
+   52|      1|        let should_be_reachable = countdown;
+   53|      1|        println!("reached");
+   54|      1|        return;
+   55|       |    };
+   56|       |
+   57|      0|    let w = if countdown > 7 {
+   58|      0|        countdown -= 4;
+   59|      0|    } else if countdown > 2 {
+   60|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
+   61|      0|            countdown = 0;
+   62|      0|        }
+   63|      0|        countdown -= 5;
+   64|       |    } else {
+   65|      0|        return;
+   66|       |    };
+   67|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while_early_return.txt b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while_early_return.txt
new file mode 100644
index 0000000..7dce94f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports-deadcode/expected_show_coverage.while_early_return.txt
@@ -0,0 +1,48 @@
+    1|       |#![allow(unused_assignments)]
+    2|       |// expect-exit-status-1
+    3|       |
+    4|       |fn main() -> Result<(),u8> {
+    5|      1|    let mut countdown = 10;
+    6|      7|    while
+    7|      7|        countdown
+    8|      7|            >
+    9|      7|        0
+   10|       |    {
+   11|       |        if
+   12|      7|            countdown
+   13|      7|                <
+   14|      7|            5
+   15|       |        {
+   16|       |            return
+   17|       |                if
+   18|      1|                    countdown
+   19|      1|                        >
+   20|      1|                    8
+   21|       |                {
+   22|      0|                    Ok(())
+   23|       |                }
+   24|       |                else
+   25|       |                {
+   26|      1|                    Err(1)
+   27|       |                }
+   28|       |                ;
+   29|       |        }
+   30|      6|        countdown
+   31|      6|            -=
+   32|      6|        1
+   33|       |        ;
+   34|       |    }
+   35|      0|    Ok(())
+   36|      1|}
+   37|       |
+   38|       |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and
+   39|       |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux
+   40|       |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program
+   41|       |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical
+   42|       |// to the coverage test for early returns, but this is a limitation that should be fixed.
+   43|       |//
+   44|       |// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`,
+   45|       |// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping
+   46|       |// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the
+   47|       |// problem exists on MSVC only).
+
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/Makefile b/src/test/run-make-fulldeps/coverage-spanview-base/Makefile
new file mode 100644
index 0000000..fa2f4ec
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/Makefile
@@ -0,0 +1,39 @@
+# needs-profiler-support
+
+# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
+# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
+# See ../coverage/coverage_tools.mk for more information.
+
+-include ../coverage/coverage_tools.mk
+
+SOURCEDIR=../coverage
+
+all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
+
+# Ensure there are no `expected` results for tests that may have been removed or renamed
+.PHONY: clear_expected_if_blessed
+clear_expected_if_blessed:
+ifdef RUSTC_BLESS_TEST
+	rm -rf expected_mir_dump.*/
+endif
+
+-include clear_expected_if_blessed
+
+%: $(SOURCEDIR)/%.rs
+	# Compile the test program with coverage instrumentation and generate relevant MIR.
+	$(RUSTC) $(SOURCEDIR)/$@.rs \
+			-Zinstrument-coverage \
+			-Clink-dead-code=$(LINK_DEAD_CODE) \
+			-Zdump-mir=InstrumentCoverage \
+			-Zdump-mir-dir="$(TMPDIR)"/mir_dump.$@
+
+ifdef RUSTC_BLESS_TEST
+	mkdir -p expected_mir_dump.$@
+	cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html expected_mir_dump.$@/
+else
+	# Check that the selected `mir_dump` files match what we expect (`--bless` refreshes `expected`)
+	mkdir -p "$(TMPDIR)"/actual_mir_dump.$@
+	rm -f "$(TMPDIR)"/actual_mir_dump.$@/*
+	cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html "$(TMPDIR)"/actual_mir_dump.$@/
+	$(DIFF) -r expected_mir_dump.$@/ "$(TMPDIR)"/actual_mir_dump.$@/
+endif
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0430\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0430\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..43f75c5
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0430\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#0} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 32"><span class="line">        <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="35:29-35:30: @0[1]: _2 = const 0_i32
+35:13-35:26: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code even" style="--layer: 1" title="36:12-36:20: @0[5]: _4 = (*((*_1).0: &amp;bool))
+36:12-36:20: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="37:13-37:27: @3[0]: _2 = const 10_i32
+36:21-38:10: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="37:13-37:27: @3[0]: _2 = const 10_i32
+36:21-38:10: @3[1]: _3 = const ()">            countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="37:13-37:27: @3[0]: _2 = const 10_i32
+36:21-38:10: @3[1]: _3 = const ()">        }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="39:9-39:23: @4[4]: _6 = const &quot;alt string 2&quot;
+39:9-39:23: @4[5]: _5 = &amp;(*_6)
+39:9-39:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+40:6-40:6: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 2".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="39:9-39:23: @4[4]: _6 = const &quot;alt string 2&quot;
+39:9-39:23: @4[5]: _5 = &amp;(*_6)
+39:9-39:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+40:6-40:6: @5.Return: return">    }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0431\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0431\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..8f07ec5
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0431\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#1} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 74"><span class="line">        <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="77:29-77:30: @0[1]: _2 = const 0_i32
+77:13-77:26: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code even" style="--layer: 1" title="78:12-78:20: @0[5]: _4 = (*((*_1).0: &amp;bool))
+78:12-78:20: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="79:13-79:27: @3[0]: _2 = const 10_i32
+78:21-80:10: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="79:13-79:27: @3[0]: _2 = const 10_i32
+78:21-80:10: @3[1]: _3 = const ()">            countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="79:13-79:27: @3[0]: _2 = const 10_i32
+78:21-80:10: @3[1]: _3 = const ()">        }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="81:9-81:23: @4[4]: _6 = const &quot;alt string 4&quot;
+81:9-81:23: @4[5]: _5 = &amp;(*_6)
+81:9-81:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+82:6-82:6: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 4".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="81:9-81:23: @4[4]: _6 = const &quot;alt string 4&quot;
+81:9-81:23: @4[5]: _5 = &amp;(*_6)
+81:9-81:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+82:6-82:6: @5.Return: return">    }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0432\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0432\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..ca9031a
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0432\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#2} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 17"><span class="line">            <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let </span><span><span class="code even" style="--layer: 1" title="20:37-20:38: @0[1]: _2 = const 0_i32
+20:21-20:34: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if </span><span><span class="code even" style="--layer: 1" title="21:20-21:28: @0[5]: _4 = (*(_1.0: &amp;bool))
+21:20-21:28: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="22:21-22:35: @3[0]: _2 = const 10_i32
+21:29-23:18: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="22:21-22:35: @3[0]: _2 = const 10_i32
+21:29-23:18: @3[1]: _3 = const ()">                    countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="22:21-22:35: @3[0]: _2 = const 10_i32
+21:29-23:18: @3[1]: _3 = const ()">                }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                </span><span><span class="code even" style="--layer: 1" title="24:17-24:31: @4[4]: _6 = const &quot;alt string 1&quot;
+24:17-24:31: @4[5]: _5 = &amp;(*_6)
+24:17-24:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+25:14-25:14: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 1".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="24:17-24:31: @4[4]: _6 = const &quot;alt string 1&quot;
+24:17-24:31: @4[5]: _5 = &amp;(*_6)
+24:17-24:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+25:14-25:14: @5.Return: return">            }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0433\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0433\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..820f8d9
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main-\173closure\0433\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#3} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 59"><span class="line">            <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let </span><span><span class="code even" style="--layer: 1" title="62:37-62:38: @0[1]: _2 = const 0_i32
+62:21-62:34: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if </span><span><span class="code even" style="--layer: 1" title="63:20-63:28: @0[5]: _4 = (*(_1.0: &amp;bool))
+63:20-63:28: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="64:21-64:35: @3[0]: _2 = const 10_i32
+63:29-65:18: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="64:21-64:35: @3[0]: _2 = const 10_i32
+63:29-65:18: @3[1]: _3 = const ()">                    countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="64:21-64:35: @3[0]: _2 = const 10_i32
+63:29-65:18: @3[1]: _3 = const ()">                }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                </span><span><span class="code even" style="--layer: 1" title="66:17-66:31: @4[4]: _6 = const &quot;alt string 3&quot;
+66:17-66:31: @4[5]: _5 = &amp;(*_6)
+66:17-66:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+67:14-67:14: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 3".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="66:17-66:31: @4[4]: _6 = const &quot;alt string 3&quot;
+66:17-66:31: @4[5]: _5 = &amp;(*_6)
+66:17-66:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+67:14-67:14: @5.Return: return">            }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..f70576c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,4505 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    // dependent conditions.</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    let is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    let is_false = ! is_true;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    let mut some_string = Some(String::from("the string content"));</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                "alt string 1".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">            }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    some_string = Some(String::from("the string content"));</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    let</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">        a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">        <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        "alt string 2".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span>;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    some_string = None;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                "alt string 3".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">            }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    some_string = None;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    let</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">        a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">        <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        "alt string 4".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span>;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">            a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">}<span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..494e6f20
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>drop_trait.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 13"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),u8&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="15:24-15:48: @0[1]: _1 = Firework { strength: const 1_i32 }
+15:9-15:21: @0[2]: FakeRead(ForLet, _1)
+17:16-17:42: @0[4]: _2 = Firework { strength: const 100_i32 }
+17:9-17:13: @0[5]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>_firecracker = Firework { strength: 1 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:24-15:48: @0[1]: _1 = Firework { strength: const 1_i32 }
+15:9-15:21: @0[2]: FakeRead(ForLet, _1)
+17:16-17:42: @0[4]: _2 = Firework { strength: const 100_i32 }
+17:9-17:13: @0[5]: FakeRead(ForLet, _2)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:24-15:48: @0[1]: _1 = Firework { strength: const 1_i32 }
+15:9-15:21: @0[2]: FakeRead(ForLet, _1)
+17:16-17:42: @0[4]: _2 = Firework { strength: const 100_i32 }
+17:9-17:13: @0[5]: FakeRead(ForLet, _2)">    let _tnt = Firework { strength: 100 }<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="19:8-19:12: @0[8]: _4 = const true
+19:8-19:12: @0[9]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>true<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="20:18-20:41: @3[6]: _21 = const main::promoted[1]
+20:18-20:41: @3[7]: _11 = &amp;(*_21)
+20:18-20:41: @3[8]: _10 = &amp;(*_11)
+20:18-20:41: @3[9]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+20:9-20:43: @3[15]: _17 = ()
+20:9-20:43: @3[16]: FakeRead(ForMatchedPlace, _17)
+20:9-20:43: @3[17]: _20 = const main::promoted[0]
+20:9-20:43: @3[18]: _15 = &amp;(*_20)
+20:9-20:43: @3[19]: _14 = &amp;(*_15)
+20:9-20:43: @3[20]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+20:9-20:43: @3.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb4, unwind: bb12]
+20:9-20:43: @4.Call: _7 = _print(move _8) -&gt; [return: bb5, unwind: bb12]
+20:9-20:43: @5[5]: _6 = const ()
+21:16-21:22: @5[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)"><span class="annotation">@1,3,4,5,9,10⦊</span>println!("Exiting with error...");</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="20:18-20:41: @3[6]: _21 = const main::promoted[1]
+20:18-20:41: @3[7]: _11 = &amp;(*_21)
+20:18-20:41: @3[8]: _10 = &amp;(*_11)
+20:18-20:41: @3[9]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+20:9-20:43: @3[15]: _17 = ()
+20:9-20:43: @3[16]: FakeRead(ForMatchedPlace, _17)
+20:9-20:43: @3[17]: _20 = const main::promoted[0]
+20:9-20:43: @3[18]: _15 = &amp;(*_20)
+20:9-20:43: @3[19]: _14 = &amp;(*_15)
+20:9-20:43: @3[20]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+20:9-20:43: @3.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb4, unwind: bb12]
+20:9-20:43: @4.Call: _7 = _print(move _8) -&gt; [return: bb5, unwind: bb12]
+20:9-20:43: @5[5]: _6 = const ()
+21:16-21:22: @5[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)">        return Err(1)<span class="annotation">⦉@1,3,4,5,9,10</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let _ = </span><span><span class="code even" style="--layer: 1" title="24:13-24:40: @2[4]: _18 = Firework { strength: const 1000_i32 }
+26:8-26:10: @6[2]: _19 = ()
+26:5-26:11: @6[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _19)"><span class="annotation">@2,6,7,8⦊</span>Firework { strength: 1000 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="24:13-24:40: @2[4]: _18 = Firework { strength: const 1000_i32 }
+26:8-26:10: @6[2]: _19 = ()
+26:5-26:11: @6[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _19)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="24:13-24:40: @2[4]: _18 = Firework { strength: const 1000_i32 }
+26:8-26:10: @6[2]: _19 = ()
+26:5-26:11: @6[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _19)">    Ok(())<span class="annotation">⦉@2,6,7,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="27:2-27:2: @11.Return: return"><span class="annotation">@11⦊</span>‸<span class="annotation">⦉@11</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.\173impl\0430\175-drop.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.\173impl\0430\175-drop.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..9530d12
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.drop_trait/drop_trait.\173impl\0430\175-drop.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>drop_trait.{impl#0}-drop - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 8"><span class="line">    <span class="code" style="--layer: 0">fn drop(&amp;mut self) </span><span><span class="code even" style="--layer: 1" title="10:18-10:36: @0[6]: _19 = const &lt;Firework as Drop&gt;::drop::promoted[0]
+10:18-10:36: @0[7]: _7 = &amp;(*_19)
+10:18-10:36: @0[8]: _6 = &amp;(*_7)
+10:18-10:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+10:38-10:51: @0[17]: _14 = &amp;((*_1).0: i32)
+10:9-10:53: @0[18]: _13 = (move _14,)
+10:9-10:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+10:9-10:53: @0[22]: _15 = (_13.0: &amp;i32)
+10:9-10:53: @0[25]: _17 = &amp;(*_15)
+10:9-10:53: @0[27]: _18 = &lt;i32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+10:9-10:53: @0.Call: _16 = ArgumentV1::new::&lt;i32&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+10:9-10:53: @1[2]: _12 = [move _16]
+10:9-10:53: @1[5]: _11 = &amp;_12
+10:9-10:53: @1[6]: _10 = &amp;(*_11)
+10:9-10:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+10:9-10:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+10:9-10:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+10:9-10:53: @3[6]: _2 = const ()
+9:24-11:6: @3[8]: _0 = const ()
+11:6-11:6: @3.Return: return"><span class="annotation">@0,1,2,3⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:18-10:36: @0[6]: _19 = const &lt;Firework as Drop&gt;::drop::promoted[0]
+10:18-10:36: @0[7]: _7 = &amp;(*_19)
+10:18-10:36: @0[8]: _6 = &amp;(*_7)
+10:18-10:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+10:38-10:51: @0[17]: _14 = &amp;((*_1).0: i32)
+10:9-10:53: @0[18]: _13 = (move _14,)
+10:9-10:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+10:9-10:53: @0[22]: _15 = (_13.0: &amp;i32)
+10:9-10:53: @0[25]: _17 = &amp;(*_15)
+10:9-10:53: @0[27]: _18 = &lt;i32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+10:9-10:53: @0.Call: _16 = ArgumentV1::new::&lt;i32&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+10:9-10:53: @1[2]: _12 = [move _16]
+10:9-10:53: @1[5]: _11 = &amp;_12
+10:9-10:53: @1[6]: _10 = &amp;(*_11)
+10:9-10:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+10:9-10:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+10:9-10:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+10:9-10:53: @3[6]: _2 = const ()
+9:24-11:6: @3[8]: _0 = const ()
+11:6-11:6: @3.Return: return">        println!("BOOM times {}!!!", self.strength);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:18-10:36: @0[6]: _19 = const &lt;Firework as Drop&gt;::drop::promoted[0]
+10:18-10:36: @0[7]: _7 = &amp;(*_19)
+10:18-10:36: @0[8]: _6 = &amp;(*_7)
+10:18-10:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+10:38-10:51: @0[17]: _14 = &amp;((*_1).0: i32)
+10:9-10:53: @0[18]: _13 = (move _14,)
+10:9-10:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+10:9-10:53: @0[22]: _15 = (_13.0: &amp;i32)
+10:9-10:53: @0[25]: _17 = &amp;(*_15)
+10:9-10:53: @0[27]: _18 = &lt;i32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+10:9-10:53: @0.Call: _16 = ArgumentV1::new::&lt;i32&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+10:9-10:53: @1[2]: _12 = [move _16]
+10:9-10:53: @1[5]: _11 = &amp;_12
+10:9-10:53: @1[6]: _10 = &amp;(*_11)
+10:9-10:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+10:9-10:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+10:9-10:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+10:9-10:53: @3[6]: _2 = const ()
+9:24-11:6: @3[8]: _0 = const ()
+11:6-11:6: @3.Return: return">    }<span class="annotation">⦉@0,1,2,3</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..6dc893d
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>generics.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 21"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),u8&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]"><span class="annotation">@0,1,2,3⦊</span>mut firecracker = Firework { strength: 1 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    firecracker.set_strength(2);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    let mut tnt = Firework { strength: 100.1 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    tnt.set_strength(200.1);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    tnt.set_strength(300.3)<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="30:8-30:12: @3[4]: _10 = const true
+30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@0,1,2,3⦊</span>true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="31:18-31:41: @6[6]: _27 = const main::promoted[1]
+31:18-31:41: @6[7]: _17 = &amp;(*_27)
+31:18-31:41: @6[8]: _16 = &amp;(*_17)
+31:18-31:41: @6[9]: _15 = move _16 as &amp;[&amp;str] (Pointer(Unsize))
+31:9-31:43: @6[15]: _23 = ()
+31:9-31:43: @6[16]: FakeRead(ForMatchedPlace, _23)
+31:9-31:43: @6[17]: _26 = const main::promoted[0]
+31:9-31:43: @6[18]: _21 = &amp;(*_26)
+31:9-31:43: @6[19]: _20 = &amp;(*_21)
+31:9-31:43: @6[20]: _19 = move _20 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+31:9-31:43: @6.Call: _14 = Arguments::new_v1(move _15, move _19) -&gt; [return: bb7, unwind: bb15]
+31:9-31:43: @7.Call: _13 = _print(move _14) -&gt; [return: bb8, unwind: bb15]
+31:9-31:43: @8[5]: _12 = const ()
+32:16-32:22: @8[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)"><span class="annotation">@4,6,7,8,12,13⦊</span>println!("Exiting with error...");</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:18-31:41: @6[6]: _27 = const main::promoted[1]
+31:18-31:41: @6[7]: _17 = &amp;(*_27)
+31:18-31:41: @6[8]: _16 = &amp;(*_17)
+31:18-31:41: @6[9]: _15 = move _16 as &amp;[&amp;str] (Pointer(Unsize))
+31:9-31:43: @6[15]: _23 = ()
+31:9-31:43: @6[16]: FakeRead(ForMatchedPlace, _23)
+31:9-31:43: @6[17]: _26 = const main::promoted[0]
+31:9-31:43: @6[18]: _21 = &amp;(*_26)
+31:9-31:43: @6[19]: _20 = &amp;(*_21)
+31:9-31:43: @6[20]: _19 = move _20 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+31:9-31:43: @6.Call: _14 = Arguments::new_v1(move _15, move _19) -&gt; [return: bb7, unwind: bb15]
+31:9-31:43: @7.Call: _13 = _print(move _14) -&gt; [return: bb8, unwind: bb15]
+31:9-31:43: @8[5]: _12 = const ()
+32:16-32:22: @8[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)">        return Err(1)<span class="annotation">⦉@4,6,7,8,12,13</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let _ = </span><span><span class="code even" style="--layer: 1" title="35:13-35:40: @5[4]: _24 = Firework::&lt;i32&gt; { strength: const 1000_i32 }
+37:8-37:10: @9[2]: _25 = ()
+37:5-37:11: @9[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _25)"><span class="annotation">@5,9,10,11⦊</span>Firework { strength: 1000 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="35:13-35:40: @5[4]: _24 = Firework::&lt;i32&gt; { strength: const 1000_i32 }
+37:8-37:10: @9[2]: _25 = ()
+37:5-37:11: @9[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _25)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="35:13-35:40: @5[4]: _24 = Firework::&lt;i32&gt; { strength: const 1000_i32 }
+37:8-37:10: @9[2]: _25 = ()
+37:5-37:11: @9[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _25)">    Ok(())<span class="annotation">⦉@5,9,10,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="38:2-38:2: @14.Return: return"><span class="annotation">@14⦊</span>‸<span class="annotation">⦉@14</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.\173impl\0430\175-set_strength.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.\173impl\0430\175-set_strength.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..e31e47b
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.\173impl\0430\175-set_strength.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>generics.{impl#0}-set_strength - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 9"><span class="line">    <span class="code" style="--layer: 0">fn set_strength(&amp;mut self, new_strength: T) </span><span><span class="code even" style="--layer: 1" title="11:25-11:37: @0[1]: _3 = _2
+11:9-11:37: @0[2]: ((*_1).0: T) = move _3
+10:49-12:6: @0[4]: _0 = const ()
+12:6-12:6: @0.Return: return"><span class="annotation">@0⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="11:25-11:37: @0[1]: _3 = _2
+11:9-11:37: @0[2]: ((*_1).0: T) = move _3
+10:49-12:6: @0[4]: _0 = const ()
+12:6-12:6: @0.Return: return">        self.strength = new_strength;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="11:25-11:37: @0[1]: _3 = _2
+11:9-11:37: @0[2]: ((*_1).0: T) = move _3
+10:49-12:6: @0[4]: _0 = const ()
+12:6-12:6: @0.Return: return">    }<span class="annotation">⦉@0</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.\173impl\0431\175-drop.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.\173impl\0431\175-drop.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..99a7df4
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.generics/generics.\173impl\0431\175-drop.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>generics.{impl#1}-drop - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 16"><span class="line">    <span class="code" style="--layer: 0">fn drop(&amp;mut self) </span><span><span class="code even" style="--layer: 1" title="18:18-18:36: @0[6]: _19 = const &lt;Firework&lt;T&gt; as Drop&gt;::drop::promoted[0]
+18:18-18:36: @0[7]: _7 = &amp;(*_19)
+18:18-18:36: @0[8]: _6 = &amp;(*_7)
+18:18-18:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+18:38-18:51: @0[17]: _14 = &amp;((*_1).0: T)
+18:9-18:53: @0[18]: _13 = (move _14,)
+18:9-18:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+18:9-18:53: @0[22]: _15 = (_13.0: &amp;T)
+18:9-18:53: @0[25]: _17 = &amp;(*_15)
+18:9-18:53: @0[27]: _18 = &lt;T as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r T, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+18:9-18:53: @0.Call: _16 = ArgumentV1::new::&lt;T&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+18:9-18:53: @1[2]: _12 = [move _16]
+18:9-18:53: @1[5]: _11 = &amp;_12
+18:9-18:53: @1[6]: _10 = &amp;(*_11)
+18:9-18:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+18:9-18:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+18:9-18:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+18:9-18:53: @3[6]: _2 = const ()
+17:24-19:6: @3[8]: _0 = const ()
+19:6-19:6: @3.Return: return"><span class="annotation">@0,1,2,3⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="18:18-18:36: @0[6]: _19 = const &lt;Firework&lt;T&gt; as Drop&gt;::drop::promoted[0]
+18:18-18:36: @0[7]: _7 = &amp;(*_19)
+18:18-18:36: @0[8]: _6 = &amp;(*_7)
+18:18-18:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+18:38-18:51: @0[17]: _14 = &amp;((*_1).0: T)
+18:9-18:53: @0[18]: _13 = (move _14,)
+18:9-18:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+18:9-18:53: @0[22]: _15 = (_13.0: &amp;T)
+18:9-18:53: @0[25]: _17 = &amp;(*_15)
+18:9-18:53: @0[27]: _18 = &lt;T as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r T, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+18:9-18:53: @0.Call: _16 = ArgumentV1::new::&lt;T&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+18:9-18:53: @1[2]: _12 = [move _16]
+18:9-18:53: @1[5]: _11 = &amp;_12
+18:9-18:53: @1[6]: _10 = &amp;(*_11)
+18:9-18:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+18:9-18:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+18:9-18:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+18:9-18:53: @3[6]: _2 = const ()
+17:24-19:6: @3[8]: _0 = const ()
+19:6-19:6: @3.Return: return">        println!("BOOM times {}!!!", self.strength);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="18:18-18:36: @0[6]: _19 = const &lt;Firework&lt;T&gt; as Drop&gt;::drop::promoted[0]
+18:18-18:36: @0[7]: _7 = &amp;(*_19)
+18:18-18:36: @0[8]: _6 = &amp;(*_7)
+18:18-18:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+18:38-18:51: @0[17]: _14 = &amp;((*_1).0: T)
+18:9-18:53: @0[18]: _13 = (move _14,)
+18:9-18:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+18:9-18:53: @0[22]: _15 = (_13.0: &amp;T)
+18:9-18:53: @0[25]: _17 = &amp;(*_15)
+18:9-18:53: @0[27]: _18 = &lt;T as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r T, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+18:9-18:53: @0.Call: _16 = ArgumentV1::new::&lt;T&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+18:9-18:53: @1[2]: _12 = [move _16]
+18:9-18:53: @1[5]: _11 = &amp;_12
+18:9-18:53: @1[6]: _10 = &amp;(*_11)
+18:9-18:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+18:9-18:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+18:9-18:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+18:9-18:53: @3[6]: _2 = const ()
+17:24-19:6: @3[8]: _0 = const ()
+19:6-19:6: @3.Return: return">    }<span class="annotation">⦉@0,1,2,3</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..0379d90
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>if.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        std::env::args().len()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    ==</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        1</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    let</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        mut</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        0<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="21:9-21:16: @3[5]: _6 = _1
+21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">            10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="28:2-28:2: @7.Return: return"><span class="annotation">@7⦊</span>‸<span class="annotation">⦉@7</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..b51c5c8
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>if_else.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)">    let mut countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)">    if</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)">        is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">            10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    else // Note coverage region difference without semicolon</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="20:9-22:16: @5[0]: _5 = const 100_i32
+20:9-22:16: @5[1]: _6 = const ()"><span class="annotation">@5⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="20:9-22:16: @5[0]: _5 = const 100_i32
+20:9-22:16: @5[1]: _6 = const ()">        =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="20:9-22:16: @5[0]: _5 = const 100_i32
+20:9-22:16: @5[1]: _6 = const ()">            100<span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="26:9-26:16: @7[3]: _8 = _1
+26:9-26:16: @7[4]: FakeRead(ForMatchedPlace, _8)"><span class="annotation">@7⦊</span>is_true<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()"><span class="annotation">@8,10⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">        countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">        =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">            10</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">        ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">    }<span class="annotation">⦉@8,10</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    else</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()"><span class="annotation">@9⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">            100</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">    }<span class="annotation">⦉@9</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="40:2-40:2: @11.Return: return"><span class="annotation">@11⦊</span>‸<span class="annotation">⦉@11</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..20c54d0
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main-InTrait-default_trait_func - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 32"><span class="line">        <span class="code" style="--layer: 0">fn default_trait_func(&amp;mut self) </span><span><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return"><span class="annotation">@0,1,2⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return">            in_func(IN_CONST);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return">            self.trait_func(IN_CONST);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return">        }<span class="annotation">⦉@0,1,2</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..49639cc
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main-in_func - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 17"><span class="line">    <span class="code" style="--layer: 0">fn in_func(a: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="19:17-19:18: @0[1]: _2 = const 1_u32
+19:13-19:14: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>b = 1<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code odd" style="--layer: 1" title="20:13-20:14: @1[3]: FakeRead(ForLet, _3)"><span class="annotation">@1,2,3,4⦊</span>c<span class="annotation">⦉@1,2,3,4</span></span></span><span class="code" style="--layer: 0"> = </span><span><span class="code even" style="--layer: 1" title="20:17-20:18: @0[5]: _4 = _1
+20:21-20:22: @0[7]: _5 = _2
+20:17-20:22: @0[8]: _6 = CheckedAdd(_4, _5)"><span class="annotation">@0⦊</span>a + b<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="21:18-21:26: @1[9]: _23 = const in_func::promoted[0]
+21:18-21:26: @1[10]: _11 = &amp;(*_23)
+21:18-21:26: @1[11]: _10 = &amp;(*_11)
+21:18-21:26: @1[12]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+21:28-21:29: @1[20]: _18 = &amp;_3
+21:9-21:30: @1[21]: _17 = (move _18,)
+21:9-21:30: @1[23]: FakeRead(ForMatchedPlace, _17)
+21:9-21:30: @1[25]: _19 = (_17.0: &amp;u32)
+21:9-21:30: @1[28]: _21 = &amp;(*_19)
+21:9-21:30: @1[30]: _22 = &lt;u32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r u32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+21:9-21:30: @1.Call: _20 = ArgumentV1::new::&lt;u32&gt;(move _21, move _22) -&gt; [return: bb2, unwind: bb5]
+21:9-21:30: @2[2]: _16 = [move _20]
+21:9-21:30: @2[5]: _15 = &amp;_16
+21:9-21:30: @2[6]: _14 = &amp;(*_15)
+21:9-21:30: @2[7]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+21:9-21:30: @2.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb3, unwind: bb5]
+21:9-21:30: @3.Call: _7 = _print(move _8) -&gt; [return: bb4, unwind: bb5]
+21:9-21:30: @4[6]: _0 = const ()
+22:6-22:6: @4.Return: return"><span class="annotation">@1,2,3,4⦊</span>println!("c = {}", c)</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="21:18-21:26: @1[9]: _23 = const in_func::promoted[0]
+21:18-21:26: @1[10]: _11 = &amp;(*_23)
+21:18-21:26: @1[11]: _10 = &amp;(*_11)
+21:18-21:26: @1[12]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+21:28-21:29: @1[20]: _18 = &amp;_3
+21:9-21:30: @1[21]: _17 = (move _18,)
+21:9-21:30: @1[23]: FakeRead(ForMatchedPlace, _17)
+21:9-21:30: @1[25]: _19 = (_17.0: &amp;u32)
+21:9-21:30: @1[28]: _21 = &amp;(*_19)
+21:9-21:30: @1[30]: _22 = &lt;u32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r u32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+21:9-21:30: @1.Call: _20 = ArgumentV1::new::&lt;u32&gt;(move _21, move _22) -&gt; [return: bb2, unwind: bb5]
+21:9-21:30: @2[2]: _16 = [move _20]
+21:9-21:30: @2[5]: _15 = &amp;_16
+21:9-21:30: @2[6]: _14 = &amp;(*_15)
+21:9-21:30: @2[7]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+21:9-21:30: @2.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb3, unwind: bb5]
+21:9-21:30: @3.Call: _7 = _print(move _8) -&gt; [return: bb4, unwind: bb5]
+21:9-21:30: @4[6]: _0 = const ()
+22:6-22:6: @4.Return: return">    }<span class="annotation">⦉@1,2,3,4</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-\173impl\0430\175-trait_func.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-\173impl\0430\175-trait_func.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..a2cf86d
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main-\173impl\0430\175-trait_func.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main-{impl#0}-trait_func - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 39"><span class="line">        <span class="code" style="--layer: 0">fn trait_func(&amp;mut self, incr: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="41:37-41:41: @0[1]: _3 = _2
+41:13-41:41: @0[2]: _4 = CheckedAdd(((*_1).0: u32), _3)"><span class="annotation">@0⦊</span>self.in_struct_field += incr<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="42:21-42:41: @1[4]: _6 = ((*_1).0: u32)
+42:13-42:42: @1.Call: _5 = in_func(move _6) -&gt; [return: bb2, unwind: bb3]
+43:10-43:10: @2.Return: return"><span class="annotation">@1,2⦊</span>in_func(self.in_struct_field);</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="42:21-42:41: @1[4]: _6 = ((*_1).0: u32)
+42:13-42:42: @1.Call: _5 = in_func(move _6) -&gt; [return: bb2, unwind: bb3]
+43:10-43:10: @2.Return: return">        }<span class="annotation">⦉@1,2</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..56557b8
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_u32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_u32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_u32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)">    let mut countdown = 0<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="10:8-10:15: @3[6]: _7 = _1
+10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="11:9-11:23: @6[0]: _5 = const 10_u32
+10:16-12:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:23: @6[0]: _5 = const 10_u32
+10:16-12:6: @6[1]: _6 = const ()">        countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:23: @6[0]: _5 = const 10_u32
+10:16-12:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    mod in_mod {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        const IN_MOD_CONST: u32 = 1000;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    fn in_func(a: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let b = 1;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let c = a + b;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        println!("c = {}", c)</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    struct InStruct {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        in_struct_field: u32,</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    const IN_CONST: u32 = 1234;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    trait InTrait {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        fn trait_func(&amp;mut self, incr: u32);</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        fn default_trait_func(&amp;mut self) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            in_func(IN_CONST);</span></span>
+<span class="line"><span class="code" style="--layer: 0">            self.trait_func(IN_CONST);</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    impl InTrait for InStruct {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        fn trait_func(&amp;mut self, incr: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            self.in_struct_field += incr;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            in_func(self.in_struct_field);</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    type InType = String;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="48:8-48:15: @7[4]: _9 = _1
+48:8-48:15: @7[5]: FakeRead(ForMatchedPlace, _9)"><span class="annotation">@7⦊</span>is_true<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="49:17-49:26: @10[2]: _11 = _5
+49:9-49:27: @10.Call: _10 = in_func(move _11) -&gt; [return: bb11, unwind: bb15]
+48:16-50:6: @11[2]: _8 = const ()"><span class="annotation">@8,10,11⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="49:17-49:26: @10[2]: _11 = _5
+49:9-49:27: @10.Call: _10 = in_func(move _11) -&gt; [return: bb11, unwind: bb15]
+48:16-50:6: @11[2]: _8 = const ()">        in_func(countdown);</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="49:17-49:26: @10[2]: _11 = _5
+49:9-49:27: @10.Call: _10 = in_func(move _11) -&gt; [return: bb11, unwind: bb15]
+48:16-50:6: @11[2]: _8 = const ()">    }<span class="annotation">⦉@8,10,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return"><span class="annotation">@12,13⦊</span>mut val = InStruct {</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">        in_struct_field: 101,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">    };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">    val.default_trait_func();</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">}<span class="annotation">⦉@12,13</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..defe743
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,160 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>lazy_boolean.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb25]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb24]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32)
+9:10-9:15: @3[4]: _5 = (_8.0: i32)
+9:17-9:22: @3[6]: _6 = (_8.1: i32)
+9:24-9:29: @3[8]: _7 = (_8.2: i32)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb25]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb24]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32)
+9:10-9:15: @3[4]: _5 = (_8.0: i32)
+9:17-9:22: @3[6]: _6 = (_8.1: i32)
+9:24-9:29: @3[8]: _7 = (_8.2: i32)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb25]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb24]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32)
+9:10-9:15: @3[4]: _5 = (_8.0: i32)
+9:17-9:22: @3[6]: _6 = (_8.1: i32)
+9:24-9:29: @3[8]: _7 = (_8.2: i32)">    let (mut a, mut b, mut c) = (0, 0, 0)<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="10:8-10:15: @3[12]: _10 = _1
+10:8-10:15: @3[13]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">        a = 1;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">        b = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">        c = 100;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="16:9-16:17: @11[2]: FakeRead(ForLet, _11)"><span class="annotation">@11⦊</span>somebool<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="18:13-18:14: @7[5]: _13 = _5
+18:17-18:18: @7[7]: _14 = _6
+18:13-18:18: @7[8]: _12 = Lt(move _13, move _14)"><span class="annotation">@7⦊</span>a &lt; b<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="20:13-20:14: @10[2]: _16 = _6
+20:17-20:18: @10[4]: _17 = _7
+20:13-20:18: @10[5]: _15 = Lt(move _16, move _17)"><span class="annotation">@10⦊</span>b &lt; c<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="23:9-23:17: @15[2]: FakeRead(ForLet, _18)"><span class="annotation">@15⦊</span>somebool<span class="annotation">⦉@15</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="25:13-25:14: @11[6]: _20 = _6
+25:17-25:18: @11[8]: _21 = _5
+25:13-25:18: @11[9]: _19 = Lt(move _20, move _21)"><span class="annotation">@11⦊</span>b &lt; a<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="27:13-27:14: @14[2]: _23 = _6
+27:17-27:18: @14[4]: _24 = _7
+27:13-27:18: @14[5]: _22 = Lt(move _23, move _24)"><span class="annotation">@14⦊</span>b &lt; c<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="30:9-30:17: @19[2]: FakeRead(ForLet, _25)"><span class="annotation">@19⦊</span>somebool<span class="annotation">⦉@19</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="32:13-32:14: @15[6]: _27 = _5
+32:17-32:18: @15[8]: _28 = _6
+32:13-32:18: @15[9]: _26 = Lt(move _27, move _28)"><span class="annotation">@15⦊</span>a &lt; b<span class="annotation">⦉@15</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        &amp;&amp;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="34:13-34:14: @18[2]: _30 = _6
+34:17-34:18: @18[4]: _31 = _7
+34:13-34:18: @18[5]: _29 = Lt(move _30, move _31)"><span class="annotation">@18⦊</span>b &lt; c<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="37:9-37:17: @23[2]: FakeRead(ForLet, _32)"><span class="annotation">@23⦊</span>somebool<span class="annotation">⦉@23</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="39:13-39:14: @19[6]: _34 = _6
+39:17-39:18: @19[8]: _35 = _5
+39:13-39:18: @19[9]: _33 = Lt(move _34, move _35)"><span class="annotation">@19⦊</span>b &lt; a<span class="annotation">⦉@19</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        &amp;&amp;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="41:13-41:14: @22[2]: _37 = _6
+41:17-41:18: @22[4]: _38 = _7
+41:13-41:18: @22[5]: _36 = Lt(move _37, move _38)"><span class="annotation">@22⦊</span>b &lt; c<span class="annotation">⦉@22</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="43:2-43:2: @23.Return: return"><span class="annotation">@23⦊</span>‸<span class="annotation">⦉@23</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..dc26c79
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>loop_break_value.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return"><span class="annotation">@0,1⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">    let result</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">        =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            loop</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">        {</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            break</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            10</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">        }</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">    ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">}<span class="annotation">⦉@0,1</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..4b21d3f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>simple_loop.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)">    let mut countdown = 0<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="12:9-12:16: @3[6]: _7 = _1
+12:9-12:16: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">            10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    loop</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="23:13-23:22: @9[3]: _11 = _5
+23:13-25:14: @9[4]: _10 = Eq(move _11, const 0_i32)
+23:13-25:14: @9[6]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@8,9⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:13-23:22: @9[3]: _11 = _5
+23:13-25:14: @9[4]: _10 = Eq(move _11, const 0_i32)
+23:13-25:14: @9[6]: FakeRead(ForMatchedPlace, _10)">                ==</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:13-23:22: @9[3]: _11 = _5
+23:13-25:14: @9[4]: _10 = Eq(move _11, const 0_i32)
+23:13-25:14: @9[6]: FakeRead(ForMatchedPlace, _10)">            0<span class="annotation">⦉@8,9</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="27:13-27:18: @12[0]: _0 = const ()"><span class="annotation">@10,12⦊</span>break<span class="annotation">⦉@10,12</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">            ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="30:9-32:10: @11[3]: _13 = CheckedSub(_5, const 1_i32)"><span class="annotation">@11⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @11[3]: _13 = CheckedSub(_5, const 1_i32)">        -=</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @11[3]: _13 = CheckedSub(_5, const 1_i32)">        1<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="35:2-35:2: @12.Return: return"><span class="annotation">@10,12⦊</span>‸<span class="annotation">⦉@10,12</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..5ba770e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,190 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>simple_match.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb22]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb21]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 1_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb22]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb21]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 1_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb22]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb21]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 1_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)">    let mut countdown = 1<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="10:8-10:15: @3[6]: _7 = _1
+10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="11:9-11:22: @6[0]: _5 = const 0_i32
+10:16-12:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:22: @6[0]: _5 = const 0_i32
+10:16-12:6: @6[1]: _6 = const ()">        countdown = 0;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:22: @6[0]: _5 = const 0_i32
+10:16-12:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="15:9-15:10: @11[2]: _17 = discriminant(_14)"><span class="annotation">@9,10,11⦊</span>for</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:9-15:10: @11[2]: _17 = discriminant(_14)">        _<span class="annotation">⦉@9,10,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    in</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="17:9-17:13: @7[4]: _9 = std::ops::Range::&lt;i32&gt; { start: const 0_i32, end: const 2_i32 }
+17:9-17:13: @7.Call: _8 = &lt;std::ops::Range&lt;i32&gt; as IntoIterator&gt;::into_iter(move _9) -&gt; [return: bb8, unwind: bb22]
+17:9-17:13: @8[1]: FakeRead(ForMatchedPlace, _8)
+17:9-17:13: @8[3]: _10 = move _8"><span class="annotation">@7,8⦊</span>0..2<span class="annotation">⦉@7,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let z</span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        match</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)"><span class="annotation">@13,15,17⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">        {</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">            x</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">            if</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">                x</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">                    &lt;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">                1<span class="annotation">⦉@13,15,17</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">            =&gt;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()"><span class="annotation">@18⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                z = countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                let y = countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                countdown = 10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">            }<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">            _</span></span>
+<span class="line"><span class="code" style="--layer: 0">            =&gt;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="40:13-40:15: @16[0]: _21 = const ()"><span class="annotation">@16⦊</span>{}<span class="annotation">⦉@16</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="43:2-43:2: @12.Return: return"><span class="annotation">@12⦊</span>‸<span class="annotation">⦉@12</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..9f99334
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>try_error_result.call - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 3"><span class="line"><span class="code" style="--layer: 0">fn call(return_error: bool) -&gt; Result&lt;(),()&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="5:8-5:20: @0[1]: _2 = _1
+5:8-5:20: @0[2]: FakeRead(ForMatchedPlace, _2)"><span class="annotation">@0⦊</span>return_error<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="6:13-6:15: @3[1]: _3 = ()
+6:9-6:16: @3[2]: _0 = std::result::Result::&lt;(), ()&gt;::Err(move _3)"><span class="annotation">@1,3⦊</span>Err(())<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="8:12-8:14: @2[1]: _4 = ()
+8:9-8:15: @2[2]: _0 = std::result::Result::&lt;(), ()&gt;::Ok(move _4)"><span class="annotation">@2⦊</span>Ok(())<span class="annotation">⦉@2</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="10:2-10:2: @4.Return: return"><span class="annotation">@4⦊</span>‸<span class="annotation">⦉@4</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..660c303
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>try_error_result.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 11"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),()&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="14:21-14:23: @0[1]: _1 = const 10_i32
+13:9-14:18: @0[2]: FakeRead(ForLet, _1)"><span class="annotation">@0,1⦊</span>mut</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="14:21-14:23: @0[1]: _1 = const 10_i32
+13:9-14:18: @0[2]: FakeRead(ForLet, _1)">        countdown = 10<span class="annotation">⦉@0,1</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="17:9-17:10: @4[2]: _12 = discriminant(_9)"><span class="annotation">@2,3,4⦊</span>for</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="17:9-17:10: @4[2]: _12 = discriminant(_9)">        _<span class="annotation">⦉@2,3,4</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    in</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="19:9-19:14: @0[6]: _4 = std::ops::Range::&lt;i32&gt; { start: const 0_i32, end: const 10_i32 }
+19:9-19:14: @0.Call: _3 = &lt;std::ops::Range&lt;i32&gt; as IntoIterator&gt;::into_iter(move _4) -&gt; [return: bb1, unwind: bb32]
+19:9-19:14: @1[1]: FakeRead(ForMatchedPlace, _3)
+19:9-19:14: @1[3]: _5 = move _3"><span class="annotation">@0,1⦊</span>0..10<span class="annotation">⦉@0,1</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="21:9-22:17: @8[12]: _17 = CheckedSub(_1, const 1_i32)"><span class="annotation">@6,8⦊</span>countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="21:9-22:17: @8[12]: _17 = CheckedSub(_1, const 1_i32)">            -= 1<span class="annotation">⦉@6,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="25:13-25:22: @9[3]: _19 = _1
+25:13-25:26: @9[4]: _18 = Lt(move _19, const 5_i32)
+25:13-25:26: @9[6]: FakeRead(ForMatchedPlace, _18)"><span class="annotation">@9⦊</span>countdown &lt; 5<span class="annotation">⦉@9</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="27:13-27:41: @12.Call: _22 = call(const true) -&gt; [return: bb13, unwind: bb32]
+27:13-27:42: @13.Call: _21 = &lt;std::result::Result&lt;(), ()&gt; as Try&gt;::into_result(move _22) -&gt; [return: bb14, unwind: bb32]
+27:13-27:42: @14[1]: FakeRead(ForMatchedPlace, _21)
+27:41-27:42: @14[2]: _23 = discriminant(_21)"><span class="annotation">@10,12,13,14⦊</span>call(/*return_error=*/ true)?<span class="annotation">⦉@10,12,13,14</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        else</span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="31:13-31:42: @11.Call: _31 = call(const false) -&gt; [return: bb21, unwind: bb32]
+31:13-31:43: @21.Call: _30 = &lt;std::result::Result&lt;(), ()&gt; as Try&gt;::into_result(move _31) -&gt; [return: bb22, unwind: bb32]
+31:13-31:43: @22[1]: FakeRead(ForMatchedPlace, _30)
+31:42-31:43: @22[2]: _32 = discriminant(_30)"><span class="annotation">@11,21,22⦊</span>call(/*return_error=*/ false)?<span class="annotation">⦉@11,21,22</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="34:8-34:10: @5[9]: _38 = ()
+34:5-34:11: @5[10]: _0 = std::result::Result::&lt;(), ()&gt;::Ok(move _38)"><span class="annotation">@5⦊</span>Ok(())<span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="35:2-35:2: @31.Return: return"><span class="annotation">@31⦊</span>‸<span class="annotation">⦉@31</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..28f1d01
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,228 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>various_conditions.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="4:25-4:26: @0[1]: _1 = const 0_u32
+4:9-4:22: @0[2]: FakeRead(ForLet, _1)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="5:8-5:12: @0[5]: _3 = const true
+5:8-5:12: @0[6]: FakeRead(ForMatchedPlace, _3)"><span class="annotation">@0⦊</span>true<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="6:9-6:23: @3[0]: _1 = const 10_u32
+5:13-7:6: @3[1]: _2 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="6:9-6:23: @3[0]: _1 = const 10_u32
+5:13-7:6: @3[1]: _2 = const ()">        countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="6:9-6:23: @3[0]: _1 = const 10_u32
+5:13-7:6: @3[1]: _2 = const ()">    }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    const B: u32 = 100;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="10:9-10:10: @25[0]: FakeRead(ForLet, _4)"><span class="annotation">@25⦊</span>x<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code odd" style="--layer: 1" title="10:16-10:25: @4[5]: _6 = _1
+10:16-10:29: @4[6]: _5 = Gt(move _6, const 7_u32)
+10:16-10:29: @4[8]: FakeRead(ForMatchedPlace, _5)"><span class="annotation">@4⦊</span>countdown &gt; 7<span class="annotation">⦉@4</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="11:9-11:23: @7[0]: _7 = CheckedSub(_1, const 4_u32)"><span class="annotation">@5,7⦊</span>countdown -= 4<span class="annotation">⦉@5,7</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="12:9-12:10: @8[1]: _4 = const B"><span class="annotation">@8⦊</span>B<span class="annotation">⦉@8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="13:15-13:24: @6[2]: _9 = _1
+13:15-13:28: @6[3]: _8 = Gt(move _9, const 2_u32)
+13:15-13:28: @6[5]: FakeRead(ForMatchedPlace, _8)"><span class="annotation">@6⦊</span>countdown &gt; 2<span class="annotation">⦉@6</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="14:12-14:21: @11[5]: _14 = _1
+14:12-14:25: @11[6]: _13 = Lt(move _14, const 1_u32)"><span class="annotation">@9,11⦊</span>countdown &lt; 1<span class="annotation">⦉@9,11</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="14:29-14:38: @18[2]: _16 = _1
+14:29-14:42: @18[3]: _15 = Gt(move _16, const 5_u32)"><span class="annotation">@18⦊</span>countdown &gt; 5<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="14:46-14:55: @14[2]: _18 = _1
+14:46-14:60: @14[3]: _17 = Ne(move _18, const 9_u32)"><span class="annotation">@14⦊</span>countdown != 9<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="15:13-15:26: @22[0]: _1 = const 0_u32
+14:61-16:10: @22[1]: _10 = const ()"><span class="annotation">@20,22⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @22[0]: _1 = const 0_u32
+14:61-16:10: @22[1]: _10 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @22[0]: _1 = const 0_u32
+14:61-16:10: @22[1]: _10 = const ()">        }<span class="annotation">⦉@20,22</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="17:9-17:23: @23[2]: _19 = CheckedSub(_1, const 5_u32)"><span class="annotation">@23⦊</span>countdown -= 5<span class="annotation">⦉@23</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="18:9-18:18: @24[1]: _4 = _1"><span class="annotation">@24⦊</span>countdown<span class="annotation">⦉@24</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="20:9-20:15: @10[0]: _0 = const ()"><span class="annotation">@10⦊</span>return<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    };</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="23:25-23:26: @25[3]: _21 = const 0_i32
+23:9-23:22: @25[4]: FakeRead(ForLet, _21)"><span class="annotation">@25⦊</span>mut countdown = 0<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="24:8-24:12: @25[7]: _23 = const true
+24:8-24:12: @25[8]: FakeRead(ForMatchedPlace, _23)"><span class="annotation">@25⦊</span>true<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="25:9-25:23: @28[0]: _21 = const 10_i32
+24:13-26:6: @28[1]: _22 = const ()"><span class="annotation">@26,28⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @28[0]: _21 = const 10_i32
+24:13-26:6: @28[1]: _22 = const ()">        countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @28[0]: _21 = const 10_i32
+24:13-26:6: @28[1]: _22 = const ()">    }<span class="annotation">⦉@26,28</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="28:8-28:17: @29[5]: _26 = _21
+28:8-28:21: @29[6]: _25 = Gt(move _26, const 7_i32)
+28:8-28:21: @29[8]: FakeRead(ForMatchedPlace, _25)"><span class="annotation">@29⦊</span>countdown &gt; 7<span class="annotation">⦉@29</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="29:9-29:23: @32[0]: _27 = CheckedSub(_21, const 4_i32)"><span class="annotation">@30,32⦊</span>countdown -= 4<span class="annotation">⦉@30,32</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="30:15-30:24: @31[2]: _29 = _21
+30:15-30:28: @31[3]: _28 = Gt(move _29, const 2_i32)
+30:15-30:28: @31[5]: FakeRead(ForMatchedPlace, _28)"><span class="annotation">@31⦊</span>countdown &gt; 2<span class="annotation">⦉@31</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="31:12-31:21: @36[5]: _34 = _21
+31:12-31:25: @36[6]: _33 = Lt(move _34, const 1_i32)"><span class="annotation">@34,36⦊</span>countdown &lt; 1<span class="annotation">⦉@34,36</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="31:29-31:38: @43[2]: _36 = _21
+31:29-31:42: @43[3]: _35 = Gt(move _36, const 5_i32)"><span class="annotation">@43⦊</span>countdown &gt; 5<span class="annotation">⦉@43</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="31:46-31:55: @39[2]: _38 = _21
+31:46-31:60: @39[3]: _37 = Ne(move _38, const 9_i32)"><span class="annotation">@39⦊</span>countdown != 9<span class="annotation">⦉@39</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="32:13-32:26: @47[0]: _21 = const 0_i32
+31:61-33:10: @47[1]: _30 = const ()"><span class="annotation">@45,47⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="32:13-32:26: @47[0]: _21 = const 0_i32
+31:61-33:10: @47[1]: _30 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="32:13-32:26: @47[0]: _21 = const 0_i32
+31:61-33:10: @47[1]: _30 = const ()">        }<span class="annotation">⦉@45,47</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="34:9-34:23: @48[2]: _39 = CheckedSub(_21, const 5_i32)"><span class="annotation">@48⦊</span>countdown -= 5<span class="annotation">⦉@48</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="36:9-36:15: @35[0]: _0 = const ()"><span class="annotation">@35⦊</span>return<span class="annotation">⦉@35</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code odd" style="--layer: 1" title="39:25-39:26: @50[3]: _41 = const 0_i32
+39:9-39:22: @50[4]: FakeRead(ForLet, _41)"><span class="annotation">@50⦊</span>mut countdown = 0<span class="annotation">⦉@50</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code odd" style="--layer: 1" title="40:8-40:12: @50[7]: _43 = const true
+40:8-40:12: @50[8]: FakeRead(ForMatchedPlace, _43)"><span class="annotation">@50⦊</span>true<span class="annotation">⦉@50</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="41:9-41:22: @53[0]: _41 = const 1_i32
+40:13-42:6: @53[1]: _42 = const ()"><span class="annotation">@51,53⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="41:9-41:22: @53[0]: _41 = const 1_i32
+40:13-42:6: @53[1]: _42 = const ()">        countdown = 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="41:9-41:22: @53[0]: _41 = const 1_i32
+40:13-42:6: @53[1]: _42 = const ()">    }<span class="annotation">⦉@51,53</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code odd" style="--layer: 1" title="44:9-44:10: @77[0]: FakeRead(ForLet, _44)"><span class="annotation">@77⦊</span>z<span class="annotation">⦉@77</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="44:16-44:25: @54[5]: _46 = _41
+44:16-44:29: @54[6]: _45 = Gt(move _46, const 7_i32)
+44:16-44:29: @54[8]: FakeRead(ForMatchedPlace, _45)"><span class="annotation">@54⦊</span>countdown &gt; 7<span class="annotation">⦉@54</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="45:9-45:23: @57[0]: _47 = CheckedSub(_41, const 4_i32)"><span class="annotation">@55,57⦊</span>countdown -= 4<span class="annotation">⦉@55,57</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="46:15-46:24: @56[2]: _49 = _41
+46:15-46:28: @56[3]: _48 = Gt(move _49, const 2_i32)
+46:15-46:28: @56[5]: FakeRead(ForMatchedPlace, _48)"><span class="annotation">@56⦊</span>countdown &gt; 2<span class="annotation">⦉@56</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="47:12-47:21: @61[5]: _54 = _41
+47:12-47:25: @61[6]: _53 = Lt(move _54, const 1_i32)"><span class="annotation">@59,61⦊</span>countdown &lt; 1<span class="annotation">⦉@59,61</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="47:29-47:38: @68[2]: _56 = _41
+47:29-47:42: @68[3]: _55 = Gt(move _56, const 5_i32)"><span class="annotation">@68⦊</span>countdown &gt; 5<span class="annotation">⦉@68</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="47:46-47:55: @64[2]: _58 = _41
+47:46-47:60: @64[3]: _57 = Ne(move _58, const 9_i32)"><span class="annotation">@64⦊</span>countdown != 9<span class="annotation">⦉@64</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="48:13-48:26: @72[0]: _41 = const 0_i32
+47:61-49:10: @72[1]: _50 = const ()"><span class="annotation">@70,72⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="48:13-48:26: @72[0]: _41 = const 0_i32
+47:61-49:10: @72[1]: _50 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="48:13-48:26: @72[0]: _41 = const 0_i32
+47:61-49:10: @72[1]: _50 = const ()">        }<span class="annotation">⦉@70,72</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="50:9-50:23: @73[2]: _59 = CheckedSub(_41, const 5_i32)"><span class="annotation">@73⦊</span>countdown -= 5<span class="annotation">⦉@73</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="52:35-52:44: @60[1]: _61 = _41
+52:13-52:32: @60[2]: FakeRead(ForLet, _61)
+53:18-53:27: @60[9]: _92 = const main::promoted[1]
+53:18-53:27: @60[10]: _67 = &amp;(*_92)
+53:18-53:27: @60[11]: _66 = &amp;(*_67)
+53:18-53:27: @60[12]: _65 = move _66 as &amp;[&amp;str] (Pointer(Unsize))
+53:9-53:29: @60[18]: _73 = ()
+53:9-53:29: @60[19]: FakeRead(ForMatchedPlace, _73)
+53:9-53:29: @60[20]: _91 = const main::promoted[0]
+53:9-53:29: @60[21]: _71 = &amp;(*_91)
+53:9-53:29: @60[22]: _70 = &amp;(*_71)
+53:9-53:29: @60[23]: _69 = move _70 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:9-53:29: @60.Call: _64 = Arguments::new_v1(move _65, move _69) -&gt; [return: bb75, unwind: bb103]
+53:9-53:29: @75.Call: _63 = _print(move _64) -&gt; [return: bb76, unwind: bb103]
+53:9-53:29: @76[5]: _62 = const ()
+54:9-54:15: @76[7]: _0 = const ()"><span class="annotation">@60,75,76⦊</span>should_be_reachable = countdown;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:35-52:44: @60[1]: _61 = _41
+52:13-52:32: @60[2]: FakeRead(ForLet, _61)
+53:18-53:27: @60[9]: _92 = const main::promoted[1]
+53:18-53:27: @60[10]: _67 = &amp;(*_92)
+53:18-53:27: @60[11]: _66 = &amp;(*_67)
+53:18-53:27: @60[12]: _65 = move _66 as &amp;[&amp;str] (Pointer(Unsize))
+53:9-53:29: @60[18]: _73 = ()
+53:9-53:29: @60[19]: FakeRead(ForMatchedPlace, _73)
+53:9-53:29: @60[20]: _91 = const main::promoted[0]
+53:9-53:29: @60[21]: _71 = &amp;(*_91)
+53:9-53:29: @60[22]: _70 = &amp;(*_71)
+53:9-53:29: @60[23]: _69 = move _70 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:9-53:29: @60.Call: _64 = Arguments::new_v1(move _65, move _69) -&gt; [return: bb75, unwind: bb103]
+53:9-53:29: @75.Call: _63 = _print(move _64) -&gt; [return: bb76, unwind: bb103]
+53:9-53:29: @76[5]: _62 = const ()
+54:9-54:15: @76[7]: _0 = const ()">        println!("reached");</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:35-52:44: @60[1]: _61 = _41
+52:13-52:32: @60[2]: FakeRead(ForLet, _61)
+53:18-53:27: @60[9]: _92 = const main::promoted[1]
+53:18-53:27: @60[10]: _67 = &amp;(*_92)
+53:18-53:27: @60[11]: _66 = &amp;(*_67)
+53:18-53:27: @60[12]: _65 = move _66 as &amp;[&amp;str] (Pointer(Unsize))
+53:9-53:29: @60[18]: _73 = ()
+53:9-53:29: @60[19]: FakeRead(ForMatchedPlace, _73)
+53:9-53:29: @60[20]: _91 = const main::promoted[0]
+53:9-53:29: @60[21]: _71 = &amp;(*_91)
+53:9-53:29: @60[22]: _70 = &amp;(*_71)
+53:9-53:29: @60[23]: _69 = move _70 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:9-53:29: @60.Call: _64 = Arguments::new_v1(move _65, move _69) -&gt; [return: bb75, unwind: bb103]
+53:9-53:29: @75.Call: _63 = _print(move _64) -&gt; [return: bb76, unwind: bb103]
+53:9-53:29: @76[5]: _62 = const ()
+54:9-54:15: @76[7]: _0 = const ()">        return<span class="annotation">⦉@60,75,76</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    };</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code odd" style="--layer: 1" title="57:9-57:10: @98[0]: FakeRead(ForLet, _74)"><span class="annotation">@98⦊</span>w<span class="annotation">⦉@98</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="57:16-57:25: @77[5]: _76 = _41
+57:16-57:29: @77[6]: _75 = Gt(move _76, const 7_i32)
+57:16-57:29: @77[8]: FakeRead(ForMatchedPlace, _75)"><span class="annotation">@77⦊</span>countdown &gt; 7<span class="annotation">⦉@77</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="58:9-58:23: @80[0]: _77 = CheckedSub(_41, const 4_i32)"><span class="annotation">@78,80⦊</span>countdown -= 4<span class="annotation">⦉@78,80</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="59:15-59:24: @79[2]: _79 = _41
+59:15-59:28: @79[3]: _78 = Gt(move _79, const 2_i32)
+59:15-59:28: @79[5]: FakeRead(ForMatchedPlace, _78)"><span class="annotation">@79⦊</span>countdown &gt; 2<span class="annotation">⦉@79</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="60:12-60:21: @84[5]: _84 = _41
+60:12-60:25: @84[6]: _83 = Lt(move _84, const 1_i32)"><span class="annotation">@82,84⦊</span>countdown &lt; 1<span class="annotation">⦉@82,84</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="60:29-60:38: @91[2]: _86 = _41
+60:29-60:42: @91[3]: _85 = Gt(move _86, const 5_i32)"><span class="annotation">@91⦊</span>countdown &gt; 5<span class="annotation">⦉@91</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="60:46-60:55: @87[2]: _88 = _41
+60:46-60:60: @87[3]: _87 = Ne(move _88, const 9_i32)"><span class="annotation">@87⦊</span>countdown != 9<span class="annotation">⦉@87</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="61:13-61:26: @95[0]: _41 = const 0_i32
+60:61-62:10: @95[1]: _80 = const ()"><span class="annotation">@93,95⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="61:13-61:26: @95[0]: _41 = const 0_i32
+60:61-62:10: @95[1]: _80 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="61:13-61:26: @95[0]: _41 = const 0_i32
+60:61-62:10: @95[1]: _80 = const ()">        }<span class="annotation">⦉@93,95</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="63:9-63:23: @96[2]: _89 = CheckedSub(_41, const 5_i32)"><span class="annotation">@96⦊</span>countdown -= 5<span class="annotation">⦉@96</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="65:9-65:15: @83[0]: _0 = const ()"><span class="annotation">@83⦊</span>return<span class="annotation">⦉@83</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    };</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="67:2-67:2: @102.Return: return"><span class="annotation">@102⦊</span>‸<span class="annotation">⦉@102</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..b96789a
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-base/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>while_early_return.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 3"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),u8&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="5:25-5:27: @0[1]: _1 = const 10_i32
+5:9-5:22: @0[2]: FakeRead(ForLet, _1)"><span class="annotation">@0⦊</span>mut countdown = 10<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@1,2⦊</span>while</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)">            &gt;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)">        0<span class="annotation">⦉@1,2</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="12:13-12:22: @5[3]: _8 = _1
+12:13-14:14: @5[4]: _7 = Lt(move _8, const 5_i32)
+12:13-14:14: @5[6]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@3,5⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="12:13-12:22: @5[3]: _8 = _1
+12:13-14:14: @5[4]: _7 = Lt(move _8, const 5_i32)
+12:13-14:14: @5[6]: FakeRead(ForMatchedPlace, _7)">                &lt;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="12:13-12:22: @5[3]: _8 = _1
+12:13-14:14: @5[4]: _7 = Lt(move _8, const 5_i32)
+12:13-14:14: @5[6]: FakeRead(ForMatchedPlace, _7)">            5<span class="annotation">⦉@3,5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            return</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    </span><span><span class="code odd" style="--layer: 1" title="18:21-18:30: @8[2]: _11 = _1
+18:21-20:22: @8[3]: _10 = Gt(move _11, const 8_i32)
+18:21-20:22: @8[5]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@6,8⦊</span>countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="18:21-18:30: @8[2]: _11 = _1
+18:21-20:22: @8[3]: _10 = Gt(move _11, const 8_i32)
+18:21-20:22: @8[5]: FakeRead(ForMatchedPlace, _10)">                        &gt;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="18:21-18:30: @8[2]: _11 = _1
+18:21-20:22: @8[3]: _10 = Gt(move _11, const 8_i32)
+18:21-20:22: @8[5]: FakeRead(ForMatchedPlace, _10)">                    8<span class="annotation">⦉@6,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    </span><span><span class="code even" style="--layer: 1" title="22:24-22:26: @11[1]: _12 = ()
+22:21-22:27: @11[2]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _12)"><span class="annotation">@9,11⦊</span>Ok(())<span class="annotation">⦉@9,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                else</span></span>
+<span class="line"><span class="code" style="--layer: 0">                {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    </span><span><span class="code odd" style="--layer: 1" title="26:21-26:27: @10[0]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)"><span class="annotation">@10⦊</span>Err(1)<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="30:9-32:10: @7[3]: _13 = CheckedSub(_1, const 1_i32)"><span class="annotation">@7⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @7[3]: _13 = CheckedSub(_1, const 1_i32)">            -=</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @7[3]: _13 = CheckedSub(_1, const 1_i32)">        1<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="35:8-35:10: @4[4]: _15 = ()
+35:5-35:11: @4[5]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _15)"><span class="annotation">@4⦊</span>Ok(())<span class="annotation">⦉@4</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="36:2-36:2: @14.Return: return"><span class="annotation">@14⦊</span>‸<span class="annotation">⦉@14</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile b/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile
new file mode 100644
index 0000000..826e85b
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/Makefile
@@ -0,0 +1,11 @@
+# needs-profiler-support
+# ignore-msvc
+
+# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038
+LINK_DEAD_CODE=yes
+
+-include ../coverage-spanview-base/Makefile
+
+# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
+# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
+# See ../coverage/coverage_tools.mk for more information.
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0430\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0430\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..43f75c5
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0430\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#0} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 32"><span class="line">        <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="35:29-35:30: @0[1]: _2 = const 0_i32
+35:13-35:26: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code even" style="--layer: 1" title="36:12-36:20: @0[5]: _4 = (*((*_1).0: &amp;bool))
+36:12-36:20: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="37:13-37:27: @3[0]: _2 = const 10_i32
+36:21-38:10: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="37:13-37:27: @3[0]: _2 = const 10_i32
+36:21-38:10: @3[1]: _3 = const ()">            countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="37:13-37:27: @3[0]: _2 = const 10_i32
+36:21-38:10: @3[1]: _3 = const ()">        }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="39:9-39:23: @4[4]: _6 = const &quot;alt string 2&quot;
+39:9-39:23: @4[5]: _5 = &amp;(*_6)
+39:9-39:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+40:6-40:6: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 2".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="39:9-39:23: @4[4]: _6 = const &quot;alt string 2&quot;
+39:9-39:23: @4[5]: _5 = &amp;(*_6)
+39:9-39:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+40:6-40:6: @5.Return: return">    }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0431\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0431\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..8f07ec5
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0431\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#1} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 74"><span class="line">        <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="77:29-77:30: @0[1]: _2 = const 0_i32
+77:13-77:26: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code even" style="--layer: 1" title="78:12-78:20: @0[5]: _4 = (*((*_1).0: &amp;bool))
+78:12-78:20: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="79:13-79:27: @3[0]: _2 = const 10_i32
+78:21-80:10: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="79:13-79:27: @3[0]: _2 = const 10_i32
+78:21-80:10: @3[1]: _3 = const ()">            countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="79:13-79:27: @3[0]: _2 = const 10_i32
+78:21-80:10: @3[1]: _3 = const ()">        }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="81:9-81:23: @4[4]: _6 = const &quot;alt string 4&quot;
+81:9-81:23: @4[5]: _5 = &amp;(*_6)
+81:9-81:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+82:6-82:6: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 4".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="81:9-81:23: @4[4]: _6 = const &quot;alt string 4&quot;
+81:9-81:23: @4[5]: _5 = &amp;(*_6)
+81:9-81:34: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+82:6-82:6: @5.Return: return">    }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0432\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0432\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..ca9031a
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0432\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#2} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 17"><span class="line">            <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let </span><span><span class="code even" style="--layer: 1" title="20:37-20:38: @0[1]: _2 = const 0_i32
+20:21-20:34: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if </span><span><span class="code even" style="--layer: 1" title="21:20-21:28: @0[5]: _4 = (*(_1.0: &amp;bool))
+21:20-21:28: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="22:21-22:35: @3[0]: _2 = const 10_i32
+21:29-23:18: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="22:21-22:35: @3[0]: _2 = const 10_i32
+21:29-23:18: @3[1]: _3 = const ()">                    countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="22:21-22:35: @3[0]: _2 = const 10_i32
+21:29-23:18: @3[1]: _3 = const ()">                }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                </span><span><span class="code even" style="--layer: 1" title="24:17-24:31: @4[4]: _6 = const &quot;alt string 1&quot;
+24:17-24:31: @4[5]: _5 = &amp;(*_6)
+24:17-24:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+25:14-25:14: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 1".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="24:17-24:31: @4[4]: _6 = const &quot;alt string 1&quot;
+24:17-24:31: @4[5]: _5 = &amp;(*_6)
+24:17-24:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+25:14-25:14: @5.Return: return">            }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0433\175.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0433\175.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..820f8d9
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main-\173closure\0433\175.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main-{closure#3} - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 59"><span class="line">            <span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let </span><span><span class="code even" style="--layer: 1" title="62:37-62:38: @0[1]: _2 = const 0_i32
+62:21-62:34: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if </span><span><span class="code even" style="--layer: 1" title="63:20-63:28: @0[5]: _4 = (*(_1.0: &amp;bool))
+63:20-63:28: @0[6]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>is_false<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="64:21-64:35: @3[0]: _2 = const 10_i32
+63:29-65:18: @3[1]: _3 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="64:21-64:35: @3[0]: _2 = const 10_i32
+63:29-65:18: @3[1]: _3 = const ()">                    countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="64:21-64:35: @3[0]: _2 = const 10_i32
+63:29-65:18: @3[1]: _3 = const ()">                }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                </span><span><span class="code even" style="--layer: 1" title="66:17-66:31: @4[4]: _6 = const &quot;alt string 3&quot;
+66:17-66:31: @4[5]: _5 = &amp;(*_6)
+66:17-66:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+67:14-67:14: @5.Return: return"><span class="annotation">@4,5⦊</span>"alt string 3".to_owned()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="66:17-66:31: @4[4]: _6 = const &quot;alt string 3&quot;
+66:17-66:31: @4[5]: _5 = &amp;(*_6)
+66:17-66:42: @4.Call: _0 = &lt;str as ToOwned&gt;::to_owned(move _5) -&gt; [return: bb5, unwind: bb6]
+67:14-67:14: @5.Return: return">            }<span class="annotation">⦉@4,5</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..f70576c
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,4505 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>closure.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    // dependent conditions.</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    let is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    let is_false = ! is_true;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    let mut some_string = Some(String::from("the string content"));</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                "alt string 1".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">            }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    some_string = Some(String::from("the string content"));</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    let</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">        a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+3:11-93:2: @33[8]: _0 = const ()">        <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        "alt string 2".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span>;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    some_string = None;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+3:11-93:2: @33[8]: _0 = const ()">            <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                "alt string 3".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">            }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    some_string = None;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    let</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">        a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+3:11-93:2: @33[8]: _0 = const ()">        <span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span><span class="code" style="--layer: 0">||</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let mut countdown = 0;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if is_false {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            countdown = 10;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        "alt string 4".to_owned()</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return"><span class="annotation">@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34⦊</span>;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">    println!(</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        "The string or alt: {}"</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        ,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        some_string</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">            .</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">            unwrap_or_else</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        (</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">            a</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">        )</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">    );</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb48]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb47]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+8:22-8:29: @3[3]: _6 = _1
+8:20-8:29: @3[4]: _5 = Not(move _6)
+8:9-8:17: @3[6]: FakeRead(ForLet, _5)
+10:32-10:66: @3.Call: _8 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb4, unwind: bb48]
+10:27-10:67: @4[0]: _7 = Option::&lt;String&gt;::Some(move _8)
+10:9-10:24: @5[1]: FakeRead(ForLet, _7)
+12:9-12:32: @5[8]: _102 = const main::promoted[3]
+12:9-12:32: @5[9]: _14 = &amp;(*_102)
+12:9-12:32: @5[10]: _13 = &amp;(*_14)
+12:9-12:32: @5[11]: _12 = move _13 as &amp;[&amp;str] (Pointer(Unsize))
+14:9-14:20: @5[21]: _23 = move _7
+14:9-26:10: @5.Call: _22 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:18:13: 25:14]&gt;(move _23, move _24) -&gt; [return: bb6, unwind: bb45]
+14:9-26:10: @6[2]: _21 = &amp;_22
+11:5-27:7: @6[3]: _20 = (move _21,)
+11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20)
+11:5-27:7: @6[7]: _26 = (_20.0: &amp;std::string::String)
+11:5-27:7: @6[10]: _28 = &amp;(*_26)
+11:5-27:7: @6[12]: _29 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+11:5-27:7: @6.Call: _27 = ArgumentV1::new::&lt;String&gt;(move _28, move _29) -&gt; [return: bb7, unwind: bb44]
+11:5-27:7: @7[2]: _19 = [move _27]
+11:5-27:7: @7[5]: _18 = &amp;_19
+11:5-27:7: @7[6]: _17 = &amp;(*_18)
+11:5-27:7: @7[7]: _16 = move _17 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -&gt; [return: bb8, unwind: bb44]
+11:5-27:7: @8.Call: _10 = _print(move _11) -&gt; [return: bb9, unwind: bb44]
+11:5-27:7: @10[6]: _9 = const ()
+29:24-29:58: @10.Call: _31 = &lt;String as From&lt;&amp;str&gt;&gt;::from(const &quot;the string content&quot;) -&gt; [return: bb11, unwind: bb46]
+29:19-29:59: @11[0]: _30 = Option::&lt;String&gt;::Some(move _31)
+33:9-40:6: @14[3]: _33 = &amp;_5
+31:9-31:10: @14[6]: FakeRead(ForLet, _32)
+42:9-42:32: @14[13]: _101 = const main::promoted[2]
+42:9-42:32: @14[14]: _39 = &amp;(*_101)
+42:9-42:32: @14[15]: _38 = &amp;(*_39)
+42:9-42:32: @14[16]: _37 = move _38 as &amp;[&amp;str] (Pointer(Unsize))
+44:9-44:20: @14[26]: _48 = move _7
+48:13-48:14: @14[28]: _49 = _32
+44:9-49:10: @14.Call: _47 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:33:9: 40:6]&gt;(move _48, move _49) -&gt; [return: bb15, unwind: bb42]
+44:9-49:10: @15[2]: _46 = &amp;_47
+41:5-50:7: @15[3]: _45 = (move _46,)
+41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45)
+41:5-50:7: @15[7]: _50 = (_45.0: &amp;std::string::String)
+41:5-50:7: @15[10]: _52 = &amp;(*_50)
+41:5-50:7: @15[12]: _53 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+41:5-50:7: @15.Call: _51 = ArgumentV1::new::&lt;String&gt;(move _52, move _53) -&gt; [return: bb16, unwind: bb41]
+41:5-50:7: @16[2]: _44 = [move _51]
+41:5-50:7: @16[5]: _43 = &amp;_44
+41:5-50:7: @16[6]: _42 = &amp;(*_43)
+41:5-50:7: @16[7]: _41 = move _42 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -&gt; [return: bb17, unwind: bb41]
+41:5-50:7: @17.Call: _35 = _print(move _36) -&gt; [return: bb18, unwind: bb41]
+41:5-50:7: @19[6]: _34 = const ()
+52:19-52:23: @19[9]: _54 = Option::&lt;String&gt;::None
+54:9-54:32: @21[7]: _100 = const main::promoted[1]
+54:9-54:32: @21[8]: _60 = &amp;(*_100)
+54:9-54:32: @21[9]: _59 = &amp;(*_60)
+54:9-54:32: @21[10]: _58 = move _59 as &amp;[&amp;str] (Pointer(Unsize))
+56:9-56:20: @21[20]: _69 = move _7
+56:9-68:10: @21.Call: _68 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:60:13: 67:14]&gt;(move _69, move _70) -&gt; [return: bb22, unwind: bb39]
+56:9-68:10: @22[2]: _67 = &amp;_68
+53:5-69:7: @22[3]: _66 = (move _67,)
+53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66)
+53:5-69:7: @22[7]: _72 = (_66.0: &amp;std::string::String)
+53:5-69:7: @22[10]: _74 = &amp;(*_72)
+53:5-69:7: @22[12]: _75 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+53:5-69:7: @22.Call: _73 = ArgumentV1::new::&lt;String&gt;(move _74, move _75) -&gt; [return: bb23, unwind: bb38]
+53:5-69:7: @23[2]: _65 = [move _73]
+53:5-69:7: @23[5]: _64 = &amp;_65
+53:5-69:7: @23[6]: _63 = &amp;(*_64)
+53:5-69:7: @23[7]: _62 = move _63 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -&gt; [return: bb24, unwind: bb38]
+53:5-69:7: @24.Call: _56 = _print(move _57) -&gt; [return: bb25, unwind: bb38]
+53:5-69:7: @26[6]: _55 = const ()
+71:19-71:23: @26[9]: _76 = Option::&lt;String&gt;::None
+73:9-73:10: @28[6]: FakeRead(ForLet, _77)
+84:9-84:32: @28[13]: _99 = const main::promoted[0]
+84:9-84:32: @28[14]: _84 = &amp;(*_99)
+84:9-84:32: @28[15]: _83 = &amp;(*_84)
+84:9-84:32: @28[16]: _82 = move _83 as &amp;[&amp;str] (Pointer(Unsize))
+86:9-86:20: @28[26]: _93 = move _7
+90:13-90:14: @28[28]: _94 = _77
+86:9-91:10: @28.Call: _92 = Option::&lt;String&gt;::unwrap_or_else::&lt;[closure@../coverage/closure.rs:75:9: 82:6]&gt;(move _93, move _94) -&gt; [return: bb29, unwind: bb36]
+86:9-91:10: @29[2]: _91 = &amp;_92
+83:5-92:7: @29[3]: _90 = (move _91,)
+83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90)
+83:5-92:7: @29[7]: _95 = (_90.0: &amp;std::string::String)
+83:5-92:7: @29[10]: _97 = &amp;(*_95)
+83:5-92:7: @29[12]: _98 = &lt;String as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r std::string::String, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+83:5-92:7: @29.Call: _96 = ArgumentV1::new::&lt;String&gt;(move _97, move _98) -&gt; [return: bb30, unwind: bb35]
+83:5-92:7: @30[2]: _89 = [move _96]
+83:5-92:7: @30[5]: _88 = &amp;_89
+83:5-92:7: @30[6]: _87 = &amp;(*_88)
+83:5-92:7: @30[7]: _86 = move _87 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -&gt; [return: bb31, unwind: bb35]
+83:5-92:7: @31.Call: _80 = _print(move _81) -&gt; [return: bb32, unwind: bb35]
+83:5-92:7: @33[6]: _79 = const ()
+3:11-93:2: @33[8]: _0 = const ()
+93:2-93:2: @34.Return: return">}<span class="annotation">⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..494e6f20
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>drop_trait.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 13"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),u8&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="15:24-15:48: @0[1]: _1 = Firework { strength: const 1_i32 }
+15:9-15:21: @0[2]: FakeRead(ForLet, _1)
+17:16-17:42: @0[4]: _2 = Firework { strength: const 100_i32 }
+17:9-17:13: @0[5]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>_firecracker = Firework { strength: 1 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:24-15:48: @0[1]: _1 = Firework { strength: const 1_i32 }
+15:9-15:21: @0[2]: FakeRead(ForLet, _1)
+17:16-17:42: @0[4]: _2 = Firework { strength: const 100_i32 }
+17:9-17:13: @0[5]: FakeRead(ForLet, _2)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:24-15:48: @0[1]: _1 = Firework { strength: const 1_i32 }
+15:9-15:21: @0[2]: FakeRead(ForLet, _1)
+17:16-17:42: @0[4]: _2 = Firework { strength: const 100_i32 }
+17:9-17:13: @0[5]: FakeRead(ForLet, _2)">    let _tnt = Firework { strength: 100 }<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="19:8-19:12: @0[8]: _4 = const true
+19:8-19:12: @0[9]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@0⦊</span>true<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="20:18-20:41: @3[6]: _21 = const main::promoted[1]
+20:18-20:41: @3[7]: _11 = &amp;(*_21)
+20:18-20:41: @3[8]: _10 = &amp;(*_11)
+20:18-20:41: @3[9]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+20:9-20:43: @3[15]: _17 = ()
+20:9-20:43: @3[16]: FakeRead(ForMatchedPlace, _17)
+20:9-20:43: @3[17]: _20 = const main::promoted[0]
+20:9-20:43: @3[18]: _15 = &amp;(*_20)
+20:9-20:43: @3[19]: _14 = &amp;(*_15)
+20:9-20:43: @3[20]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+20:9-20:43: @3.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb4, unwind: bb12]
+20:9-20:43: @4.Call: _7 = _print(move _8) -&gt; [return: bb5, unwind: bb12]
+20:9-20:43: @5[5]: _6 = const ()
+21:16-21:22: @5[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)"><span class="annotation">@1,3,4,5,9,10⦊</span>println!("Exiting with error...");</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="20:18-20:41: @3[6]: _21 = const main::promoted[1]
+20:18-20:41: @3[7]: _11 = &amp;(*_21)
+20:18-20:41: @3[8]: _10 = &amp;(*_11)
+20:18-20:41: @3[9]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+20:9-20:43: @3[15]: _17 = ()
+20:9-20:43: @3[16]: FakeRead(ForMatchedPlace, _17)
+20:9-20:43: @3[17]: _20 = const main::promoted[0]
+20:9-20:43: @3[18]: _15 = &amp;(*_20)
+20:9-20:43: @3[19]: _14 = &amp;(*_15)
+20:9-20:43: @3[20]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+20:9-20:43: @3.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb4, unwind: bb12]
+20:9-20:43: @4.Call: _7 = _print(move _8) -&gt; [return: bb5, unwind: bb12]
+20:9-20:43: @5[5]: _6 = const ()
+21:16-21:22: @5[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)">        return Err(1)<span class="annotation">⦉@1,3,4,5,9,10</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let _ = </span><span><span class="code even" style="--layer: 1" title="24:13-24:40: @2[4]: _18 = Firework { strength: const 1000_i32 }
+26:8-26:10: @6[2]: _19 = ()
+26:5-26:11: @6[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _19)"><span class="annotation">@2,6,7,8⦊</span>Firework { strength: 1000 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="24:13-24:40: @2[4]: _18 = Firework { strength: const 1000_i32 }
+26:8-26:10: @6[2]: _19 = ()
+26:5-26:11: @6[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _19)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="24:13-24:40: @2[4]: _18 = Firework { strength: const 1000_i32 }
+26:8-26:10: @6[2]: _19 = ()
+26:5-26:11: @6[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _19)">    Ok(())<span class="annotation">⦉@2,6,7,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="27:2-27:2: @11.Return: return"><span class="annotation">@11⦊</span>‸<span class="annotation">⦉@11</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.\173impl\0430\175-drop.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.\173impl\0430\175-drop.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..9530d12
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.drop_trait/drop_trait.\173impl\0430\175-drop.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>drop_trait.{impl#0}-drop - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 8"><span class="line">    <span class="code" style="--layer: 0">fn drop(&amp;mut self) </span><span><span class="code even" style="--layer: 1" title="10:18-10:36: @0[6]: _19 = const &lt;Firework as Drop&gt;::drop::promoted[0]
+10:18-10:36: @0[7]: _7 = &amp;(*_19)
+10:18-10:36: @0[8]: _6 = &amp;(*_7)
+10:18-10:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+10:38-10:51: @0[17]: _14 = &amp;((*_1).0: i32)
+10:9-10:53: @0[18]: _13 = (move _14,)
+10:9-10:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+10:9-10:53: @0[22]: _15 = (_13.0: &amp;i32)
+10:9-10:53: @0[25]: _17 = &amp;(*_15)
+10:9-10:53: @0[27]: _18 = &lt;i32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+10:9-10:53: @0.Call: _16 = ArgumentV1::new::&lt;i32&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+10:9-10:53: @1[2]: _12 = [move _16]
+10:9-10:53: @1[5]: _11 = &amp;_12
+10:9-10:53: @1[6]: _10 = &amp;(*_11)
+10:9-10:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+10:9-10:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+10:9-10:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+10:9-10:53: @3[6]: _2 = const ()
+9:24-11:6: @3[8]: _0 = const ()
+11:6-11:6: @3.Return: return"><span class="annotation">@0,1,2,3⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:18-10:36: @0[6]: _19 = const &lt;Firework as Drop&gt;::drop::promoted[0]
+10:18-10:36: @0[7]: _7 = &amp;(*_19)
+10:18-10:36: @0[8]: _6 = &amp;(*_7)
+10:18-10:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+10:38-10:51: @0[17]: _14 = &amp;((*_1).0: i32)
+10:9-10:53: @0[18]: _13 = (move _14,)
+10:9-10:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+10:9-10:53: @0[22]: _15 = (_13.0: &amp;i32)
+10:9-10:53: @0[25]: _17 = &amp;(*_15)
+10:9-10:53: @0[27]: _18 = &lt;i32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+10:9-10:53: @0.Call: _16 = ArgumentV1::new::&lt;i32&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+10:9-10:53: @1[2]: _12 = [move _16]
+10:9-10:53: @1[5]: _11 = &amp;_12
+10:9-10:53: @1[6]: _10 = &amp;(*_11)
+10:9-10:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+10:9-10:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+10:9-10:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+10:9-10:53: @3[6]: _2 = const ()
+9:24-11:6: @3[8]: _0 = const ()
+11:6-11:6: @3.Return: return">        println!("BOOM times {}!!!", self.strength);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:18-10:36: @0[6]: _19 = const &lt;Firework as Drop&gt;::drop::promoted[0]
+10:18-10:36: @0[7]: _7 = &amp;(*_19)
+10:18-10:36: @0[8]: _6 = &amp;(*_7)
+10:18-10:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+10:38-10:51: @0[17]: _14 = &amp;((*_1).0: i32)
+10:9-10:53: @0[18]: _13 = (move _14,)
+10:9-10:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+10:9-10:53: @0[22]: _15 = (_13.0: &amp;i32)
+10:9-10:53: @0[25]: _17 = &amp;(*_15)
+10:9-10:53: @0[27]: _18 = &lt;i32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+10:9-10:53: @0.Call: _16 = ArgumentV1::new::&lt;i32&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+10:9-10:53: @1[2]: _12 = [move _16]
+10:9-10:53: @1[5]: _11 = &amp;_12
+10:9-10:53: @1[6]: _10 = &amp;(*_11)
+10:9-10:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+10:9-10:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+10:9-10:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+10:9-10:53: @3[6]: _2 = const ()
+9:24-11:6: @3[8]: _0 = const ()
+11:6-11:6: @3.Return: return">    }<span class="annotation">⦉@0,1,2,3</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..6dc893d
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>generics.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 21"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),u8&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]"><span class="annotation">@0,1,2,3⦊</span>mut firecracker = Firework { strength: 1 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    firecracker.set_strength(2);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    let mut tnt = Firework { strength: 100.1 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    tnt.set_strength(200.1);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:27-23:51: @0[1]: _1 = Firework::&lt;i32&gt; { strength: const 1_i32 }
+23:9-23:24: @0[2]: FakeRead(ForLet, _1)
+24:5-24:16: @0[5]: _3 = &amp;mut _1
+24:5-24:32: @0.Call: _2 = Firework::&lt;i32&gt;::set_strength(move _3, const 2_i32) -&gt; [return: bb1, unwind: bb16]
+26:19-26:47: @1[3]: _4 = Firework::&lt;f64&gt; { strength: const 100.09999999999999f64 }
+26:9-26:16: @1[4]: FakeRead(ForLet, _4)
+27:5-27:8: @1[7]: _6 = &amp;mut _4
+27:5-27:28: @1.Call: _5 = Firework::&lt;f64&gt;::set_strength(move _6, const 200.09999999999999f64) -&gt; [return: bb2, unwind: bb15]
+28:5-28:8: @2[4]: _8 = &amp;mut _4
+28:5-28:28: @2.Call: _7 = Firework::&lt;f64&gt;::set_strength(move _8, const 300.30000000000001f64) -&gt; [return: bb3, unwind: bb15]">    tnt.set_strength(300.3)<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="30:8-30:12: @3[4]: _10 = const true
+30:8-30:12: @3[5]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@0,1,2,3⦊</span>true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="31:18-31:41: @6[6]: _27 = const main::promoted[1]
+31:18-31:41: @6[7]: _17 = &amp;(*_27)
+31:18-31:41: @6[8]: _16 = &amp;(*_17)
+31:18-31:41: @6[9]: _15 = move _16 as &amp;[&amp;str] (Pointer(Unsize))
+31:9-31:43: @6[15]: _23 = ()
+31:9-31:43: @6[16]: FakeRead(ForMatchedPlace, _23)
+31:9-31:43: @6[17]: _26 = const main::promoted[0]
+31:9-31:43: @6[18]: _21 = &amp;(*_26)
+31:9-31:43: @6[19]: _20 = &amp;(*_21)
+31:9-31:43: @6[20]: _19 = move _20 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+31:9-31:43: @6.Call: _14 = Arguments::new_v1(move _15, move _19) -&gt; [return: bb7, unwind: bb15]
+31:9-31:43: @7.Call: _13 = _print(move _14) -&gt; [return: bb8, unwind: bb15]
+31:9-31:43: @8[5]: _12 = const ()
+32:16-32:22: @8[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)"><span class="annotation">@4,6,7,8,12,13⦊</span>println!("Exiting with error...");</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:18-31:41: @6[6]: _27 = const main::promoted[1]
+31:18-31:41: @6[7]: _17 = &amp;(*_27)
+31:18-31:41: @6[8]: _16 = &amp;(*_17)
+31:18-31:41: @6[9]: _15 = move _16 as &amp;[&amp;str] (Pointer(Unsize))
+31:9-31:43: @6[15]: _23 = ()
+31:9-31:43: @6[16]: FakeRead(ForMatchedPlace, _23)
+31:9-31:43: @6[17]: _26 = const main::promoted[0]
+31:9-31:43: @6[18]: _21 = &amp;(*_26)
+31:9-31:43: @6[19]: _20 = &amp;(*_21)
+31:9-31:43: @6[20]: _19 = move _20 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+31:9-31:43: @6.Call: _14 = Arguments::new_v1(move _15, move _19) -&gt; [return: bb7, unwind: bb15]
+31:9-31:43: @7.Call: _13 = _print(move _14) -&gt; [return: bb8, unwind: bb15]
+31:9-31:43: @8[5]: _12 = const ()
+32:16-32:22: @8[7]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)">        return Err(1)<span class="annotation">⦉@4,6,7,8,12,13</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let _ = </span><span><span class="code even" style="--layer: 1" title="35:13-35:40: @5[4]: _24 = Firework::&lt;i32&gt; { strength: const 1000_i32 }
+37:8-37:10: @9[2]: _25 = ()
+37:5-37:11: @9[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _25)"><span class="annotation">@5,9,10,11⦊</span>Firework { strength: 1000 };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="35:13-35:40: @5[4]: _24 = Firework::&lt;i32&gt; { strength: const 1000_i32 }
+37:8-37:10: @9[2]: _25 = ()
+37:5-37:11: @9[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _25)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="35:13-35:40: @5[4]: _24 = Firework::&lt;i32&gt; { strength: const 1000_i32 }
+37:8-37:10: @9[2]: _25 = ()
+37:5-37:11: @9[3]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _25)">    Ok(())<span class="annotation">⦉@5,9,10,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="38:2-38:2: @14.Return: return"><span class="annotation">@14⦊</span>‸<span class="annotation">⦉@14</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.\173impl\0430\175-set_strength.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.\173impl\0430\175-set_strength.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..e31e47b
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.\173impl\0430\175-set_strength.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>generics.{impl#0}-set_strength - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 9"><span class="line">    <span class="code" style="--layer: 0">fn set_strength(&amp;mut self, new_strength: T) </span><span><span class="code even" style="--layer: 1" title="11:25-11:37: @0[1]: _3 = _2
+11:9-11:37: @0[2]: ((*_1).0: T) = move _3
+10:49-12:6: @0[4]: _0 = const ()
+12:6-12:6: @0.Return: return"><span class="annotation">@0⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="11:25-11:37: @0[1]: _3 = _2
+11:9-11:37: @0[2]: ((*_1).0: T) = move _3
+10:49-12:6: @0[4]: _0 = const ()
+12:6-12:6: @0.Return: return">        self.strength = new_strength;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="11:25-11:37: @0[1]: _3 = _2
+11:9-11:37: @0[2]: ((*_1).0: T) = move _3
+10:49-12:6: @0[4]: _0 = const ()
+12:6-12:6: @0.Return: return">    }<span class="annotation">⦉@0</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.\173impl\0431\175-drop.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.\173impl\0431\175-drop.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..99a7df4
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.generics/generics.\173impl\0431\175-drop.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>generics.{impl#1}-drop - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 16"><span class="line">    <span class="code" style="--layer: 0">fn drop(&amp;mut self) </span><span><span class="code even" style="--layer: 1" title="18:18-18:36: @0[6]: _19 = const &lt;Firework&lt;T&gt; as Drop&gt;::drop::promoted[0]
+18:18-18:36: @0[7]: _7 = &amp;(*_19)
+18:18-18:36: @0[8]: _6 = &amp;(*_7)
+18:18-18:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+18:38-18:51: @0[17]: _14 = &amp;((*_1).0: T)
+18:9-18:53: @0[18]: _13 = (move _14,)
+18:9-18:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+18:9-18:53: @0[22]: _15 = (_13.0: &amp;T)
+18:9-18:53: @0[25]: _17 = &amp;(*_15)
+18:9-18:53: @0[27]: _18 = &lt;T as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r T, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+18:9-18:53: @0.Call: _16 = ArgumentV1::new::&lt;T&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+18:9-18:53: @1[2]: _12 = [move _16]
+18:9-18:53: @1[5]: _11 = &amp;_12
+18:9-18:53: @1[6]: _10 = &amp;(*_11)
+18:9-18:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+18:9-18:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+18:9-18:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+18:9-18:53: @3[6]: _2 = const ()
+17:24-19:6: @3[8]: _0 = const ()
+19:6-19:6: @3.Return: return"><span class="annotation">@0,1,2,3⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="18:18-18:36: @0[6]: _19 = const &lt;Firework&lt;T&gt; as Drop&gt;::drop::promoted[0]
+18:18-18:36: @0[7]: _7 = &amp;(*_19)
+18:18-18:36: @0[8]: _6 = &amp;(*_7)
+18:18-18:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+18:38-18:51: @0[17]: _14 = &amp;((*_1).0: T)
+18:9-18:53: @0[18]: _13 = (move _14,)
+18:9-18:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+18:9-18:53: @0[22]: _15 = (_13.0: &amp;T)
+18:9-18:53: @0[25]: _17 = &amp;(*_15)
+18:9-18:53: @0[27]: _18 = &lt;T as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r T, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+18:9-18:53: @0.Call: _16 = ArgumentV1::new::&lt;T&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+18:9-18:53: @1[2]: _12 = [move _16]
+18:9-18:53: @1[5]: _11 = &amp;_12
+18:9-18:53: @1[6]: _10 = &amp;(*_11)
+18:9-18:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+18:9-18:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+18:9-18:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+18:9-18:53: @3[6]: _2 = const ()
+17:24-19:6: @3[8]: _0 = const ()
+19:6-19:6: @3.Return: return">        println!("BOOM times {}!!!", self.strength);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="18:18-18:36: @0[6]: _19 = const &lt;Firework&lt;T&gt; as Drop&gt;::drop::promoted[0]
+18:18-18:36: @0[7]: _7 = &amp;(*_19)
+18:18-18:36: @0[8]: _6 = &amp;(*_7)
+18:18-18:36: @0[9]: _5 = move _6 as &amp;[&amp;str] (Pointer(Unsize))
+18:38-18:51: @0[17]: _14 = &amp;((*_1).0: T)
+18:9-18:53: @0[18]: _13 = (move _14,)
+18:9-18:53: @0[20]: FakeRead(ForMatchedPlace, _13)
+18:9-18:53: @0[22]: _15 = (_13.0: &amp;T)
+18:9-18:53: @0[25]: _17 = &amp;(*_15)
+18:9-18:53: @0[27]: _18 = &lt;T as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r T, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+18:9-18:53: @0.Call: _16 = ArgumentV1::new::&lt;T&gt;(move _17, move _18) -&gt; [return: bb1, unwind: bb4]
+18:9-18:53: @1[2]: _12 = [move _16]
+18:9-18:53: @1[5]: _11 = &amp;_12
+18:9-18:53: @1[6]: _10 = &amp;(*_11)
+18:9-18:53: @1[7]: _9 = move _10 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+18:9-18:53: @1.Call: _4 = Arguments::new_v1(move _5, move _9) -&gt; [return: bb2, unwind: bb4]
+18:9-18:53: @2.Call: _3 = _print(move _4) -&gt; [return: bb3, unwind: bb4]
+18:9-18:53: @3[6]: _2 = const ()
+17:24-19:6: @3[8]: _0 = const ()
+19:6-19:6: @3.Return: return">    }<span class="annotation">⦉@0,1,2,3</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..0379d90
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if/if.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>if.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        std::env::args().len()</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    ==</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        1</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    let</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        mut</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">    =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="10:9-10:25: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb9]
+10:9-10:25: @1[0]: _3 = &amp;_4
+10:9-10:31: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb8]
+10:9-12:10: @2[1]: _1 = Eq(move _2, const 1_usize)
+8:5-8:12: @2[3]: FakeRead(ForLet, _1)
+18:9-18:10: @3[2]: _5 = const 0_i32
+15:9-16:14: @3[3]: FakeRead(ForLet, _5)">        0<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="21:9-21:16: @3[5]: _6 = _1
+21:9-21:16: @3[6]: FakeRead(ForMatchedPlace, _6)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">            10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="23:9-25:15: @6[0]: _5 = const 10_i32
+22:5-27:6: @6[1]: _0 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="28:2-28:2: @7.Return: return"><span class="annotation">@7⦊</span>‸<span class="annotation">⦉@7</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..b51c5c8
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.if_else/if_else.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>if_else.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)">    let mut countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)">    if</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb13]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb12]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)
+11:9-11:16: @3[6]: _7 = _1
+11:9-11:16: @3[7]: FakeRead(ForMatchedPlace, _7)">        is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">            10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="13:9-15:15: @6[0]: _5 = const 10_i32
+12:5-17:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    else // Note coverage region difference without semicolon</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="20:9-22:16: @5[0]: _5 = const 100_i32
+20:9-22:16: @5[1]: _6 = const ()"><span class="annotation">@5⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="20:9-22:16: @5[0]: _5 = const 100_i32
+20:9-22:16: @5[1]: _6 = const ()">        =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="20:9-22:16: @5[0]: _5 = const 100_i32
+20:9-22:16: @5[1]: _6 = const ()">            100<span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="26:9-26:16: @7[3]: _8 = _1
+26:9-26:16: @7[4]: FakeRead(ForMatchedPlace, _8)"><span class="annotation">@7⦊</span>is_true<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()"><span class="annotation">@8,10⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">        countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">        =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">            10</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">        ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="28:9-30:15: @10[0]: _5 = const 10_i32
+27:5-32:6: @10[1]: _0 = const ()">    }<span class="annotation">⦉@8,10</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    else</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()"><span class="annotation">@9⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">            100</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="35:9-37:16: @9[0]: _5 = const 100_i32
+34:5-39:6: @9[1]: _0 = const ()">    }<span class="annotation">⦉@9</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="40:2-40:2: @11.Return: return"><span class="annotation">@11⦊</span>‸<span class="annotation">⦉@11</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..20c54d0
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-InTrait-default_trait_func.-------.InstrumentCoverage.0.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main-InTrait-default_trait_func - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 32"><span class="line">        <span class="code" style="--layer: 0">fn default_trait_func(&amp;mut self) </span><span><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return"><span class="annotation">@0,1,2⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return">            in_func(IN_CONST);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return">            self.trait_func(IN_CONST);</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="34:13-34:30: @0.Call: _2 = in_func(const IN_CONST) -&gt; [return: bb1, unwind: bb3]
+35:13-35:17: @1[3]: _4 = &amp;mut (*_1)
+35:13-35:38: @1.Call: _3 = &lt;Self as InTrait&gt;::trait_func(move _4, const IN_CONST) -&gt; [return: bb2, unwind: bb3]
+33:42-36:10: @2[2]: _0 = const ()
+36:10-36:10: @2.Return: return">        }<span class="annotation">⦉@0,1,2</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..49639cc
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-in_func.-------.InstrumentCoverage.0.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main-in_func - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 17"><span class="line">    <span class="code" style="--layer: 0">fn in_func(a: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="19:17-19:18: @0[1]: _2 = const 1_u32
+19:13-19:14: @0[2]: FakeRead(ForLet, _2)"><span class="annotation">@0⦊</span>b = 1<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code odd" style="--layer: 1" title="20:13-20:14: @1[3]: FakeRead(ForLet, _3)"><span class="annotation">@1,2,3,4⦊</span>c<span class="annotation">⦉@1,2,3,4</span></span></span><span class="code" style="--layer: 0"> = </span><span><span class="code even" style="--layer: 1" title="20:17-20:18: @0[5]: _4 = _1
+20:21-20:22: @0[7]: _5 = _2
+20:17-20:22: @0[8]: _6 = CheckedAdd(_4, _5)"><span class="annotation">@0⦊</span>a + b<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="21:18-21:26: @1[9]: _23 = const in_func::promoted[0]
+21:18-21:26: @1[10]: _11 = &amp;(*_23)
+21:18-21:26: @1[11]: _10 = &amp;(*_11)
+21:18-21:26: @1[12]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+21:28-21:29: @1[20]: _18 = &amp;_3
+21:9-21:30: @1[21]: _17 = (move _18,)
+21:9-21:30: @1[23]: FakeRead(ForMatchedPlace, _17)
+21:9-21:30: @1[25]: _19 = (_17.0: &amp;u32)
+21:9-21:30: @1[28]: _21 = &amp;(*_19)
+21:9-21:30: @1[30]: _22 = &lt;u32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r u32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+21:9-21:30: @1.Call: _20 = ArgumentV1::new::&lt;u32&gt;(move _21, move _22) -&gt; [return: bb2, unwind: bb5]
+21:9-21:30: @2[2]: _16 = [move _20]
+21:9-21:30: @2[5]: _15 = &amp;_16
+21:9-21:30: @2[6]: _14 = &amp;(*_15)
+21:9-21:30: @2[7]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+21:9-21:30: @2.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb3, unwind: bb5]
+21:9-21:30: @3.Call: _7 = _print(move _8) -&gt; [return: bb4, unwind: bb5]
+21:9-21:30: @4[6]: _0 = const ()
+22:6-22:6: @4.Return: return"><span class="annotation">@1,2,3,4⦊</span>println!("c = {}", c)</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="21:18-21:26: @1[9]: _23 = const in_func::promoted[0]
+21:18-21:26: @1[10]: _11 = &amp;(*_23)
+21:18-21:26: @1[11]: _10 = &amp;(*_11)
+21:18-21:26: @1[12]: _9 = move _10 as &amp;[&amp;str] (Pointer(Unsize))
+21:28-21:29: @1[20]: _18 = &amp;_3
+21:9-21:30: @1[21]: _17 = (move _18,)
+21:9-21:30: @1[23]: FakeRead(ForMatchedPlace, _17)
+21:9-21:30: @1[25]: _19 = (_17.0: &amp;u32)
+21:9-21:30: @1[28]: _21 = &amp;(*_19)
+21:9-21:30: @1[30]: _22 = &lt;u32 as std::fmt::Display&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r u32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+21:9-21:30: @1.Call: _20 = ArgumentV1::new::&lt;u32&gt;(move _21, move _22) -&gt; [return: bb2, unwind: bb5]
+21:9-21:30: @2[2]: _16 = [move _20]
+21:9-21:30: @2[5]: _15 = &amp;_16
+21:9-21:30: @2[6]: _14 = &amp;(*_15)
+21:9-21:30: @2[7]: _13 = move _14 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+21:9-21:30: @2.Call: _8 = Arguments::new_v1(move _9, move _13) -&gt; [return: bb3, unwind: bb5]
+21:9-21:30: @3.Call: _7 = _print(move _8) -&gt; [return: bb4, unwind: bb5]
+21:9-21:30: @4[6]: _0 = const ()
+22:6-22:6: @4.Return: return">    }<span class="annotation">⦉@1,2,3,4</span></span></span></span></div>
+</body>
+</html>
diff --git "a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-\173impl\0430\175-trait_func.-------.InstrumentCoverage.0.html" "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-\173impl\0430\175-trait_func.-------.InstrumentCoverage.0.html"
new file mode 100644
index 0000000..a2cf86d
--- /dev/null
+++ "b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main-\173impl\0430\175-trait_func.-------.InstrumentCoverage.0.html"
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main-{impl#0}-trait_func - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 39"><span class="line">        <span class="code" style="--layer: 0">fn trait_func(&amp;mut self, incr: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="41:37-41:41: @0[1]: _3 = _2
+41:13-41:41: @0[2]: _4 = CheckedAdd(((*_1).0: u32), _3)"><span class="annotation">@0⦊</span>self.in_struct_field += incr<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="42:21-42:41: @1[4]: _6 = ((*_1).0: u32)
+42:13-42:42: @1.Call: _5 = in_func(move _6) -&gt; [return: bb2, unwind: bb3]
+43:10-43:10: @2.Return: return"><span class="annotation">@1,2⦊</span>in_func(self.in_struct_field);</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="42:21-42:41: @1[4]: _6 = ((*_1).0: u32)
+42:13-42:42: @1.Call: _5 = in_func(move _6) -&gt; [return: bb2, unwind: bb3]
+43:10-43:10: @2.Return: return">        }<span class="annotation">⦉@1,2</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..56557b8
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.inner_items/inner_items.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>inner_items.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_u32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_u32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_u32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)">    let mut countdown = 0<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="10:8-10:15: @3[6]: _7 = _1
+10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="11:9-11:23: @6[0]: _5 = const 10_u32
+10:16-12:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:23: @6[0]: _5 = const 10_u32
+10:16-12:6: @6[1]: _6 = const ()">        countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:23: @6[0]: _5 = const 10_u32
+10:16-12:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    mod in_mod {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        const IN_MOD_CONST: u32 = 1000;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    fn in_func(a: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let b = 1;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let c = a + b;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        println!("c = {}", c)</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    struct InStruct {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        in_struct_field: u32,</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    const IN_CONST: u32 = 1234;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    trait InTrait {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        fn trait_func(&amp;mut self, incr: u32);</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        fn default_trait_func(&amp;mut self) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            in_func(IN_CONST);</span></span>
+<span class="line"><span class="code" style="--layer: 0">            self.trait_func(IN_CONST);</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    impl InTrait for InStruct {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        fn trait_func(&amp;mut self, incr: u32) {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            self.in_struct_field += incr;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            in_func(self.in_struct_field);</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    type InType = String;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="48:8-48:15: @7[4]: _9 = _1
+48:8-48:15: @7[5]: FakeRead(ForMatchedPlace, _9)"><span class="annotation">@7⦊</span>is_true<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="49:17-49:26: @10[2]: _11 = _5
+49:9-49:27: @10.Call: _10 = in_func(move _11) -&gt; [return: bb11, unwind: bb15]
+48:16-50:6: @11[2]: _8 = const ()"><span class="annotation">@8,10,11⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="49:17-49:26: @10[2]: _11 = _5
+49:9-49:27: @10.Call: _10 = in_func(move _11) -&gt; [return: bb11, unwind: bb15]
+48:16-50:6: @11[2]: _8 = const ()">        in_func(countdown);</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="49:17-49:26: @10[2]: _11 = _5
+49:9-49:27: @10.Call: _10 = in_func(move _11) -&gt; [return: bb11, unwind: bb15]
+48:16-50:6: @11[2]: _8 = const ()">    }<span class="annotation">⦉@8,10,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return"><span class="annotation">@12,13⦊</span>mut val = InStruct {</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">        in_struct_field: 101,</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">    };</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">    val.default_trait_func();</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:19-54:6: @12[3]: _12 = InStruct { in_struct_field: const 101_u32 }
+52:9-52:16: @12[4]: FakeRead(ForLet, _12)
+56:5-56:8: @12[7]: _14 = &amp;mut _12
+56:5-56:29: @12.Call: _13 = &lt;InStruct as InTrait&gt;::default_trait_func(move _14) -&gt; [return: bb13, unwind: bb15]
+57:2-57:2: @13.Return: return">}<span class="annotation">⦉@12,13</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..defe743
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.lazy_boolean/lazy_boolean.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,160 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>lazy_boolean.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb25]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb24]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32)
+9:10-9:15: @3[4]: _5 = (_8.0: i32)
+9:17-9:22: @3[6]: _6 = (_8.1: i32)
+9:24-9:29: @3[8]: _7 = (_8.2: i32)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb25]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb24]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32)
+9:10-9:15: @3[4]: _5 = (_8.0: i32)
+9:17-9:22: @3[6]: _6 = (_8.1: i32)
+9:24-9:29: @3[8]: _7 = (_8.2: i32)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb25]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb24]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:33-9:42: @3[2]: _8 = (const 0_i32, const 0_i32, const 0_i32)
+9:10-9:15: @3[4]: _5 = (_8.0: i32)
+9:17-9:22: @3[6]: _6 = (_8.1: i32)
+9:24-9:29: @3[8]: _7 = (_8.2: i32)">    let (mut a, mut b, mut c) = (0, 0, 0)<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="10:8-10:15: @3[12]: _10 = _1
+10:8-10:15: @3[13]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">        a = 1;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">        b = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">        c = 100;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:14: @6[0]: _5 = const 1_i32
+12:9-12:15: @6[1]: _6 = const 10_i32
+13:9-13:16: @6[2]: _7 = const 100_i32
+10:16-14:6: @6[3]: _9 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="16:9-16:17: @11[2]: FakeRead(ForLet, _11)"><span class="annotation">@11⦊</span>somebool<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="18:13-18:14: @7[5]: _13 = _5
+18:17-18:18: @7[7]: _14 = _6
+18:13-18:18: @7[8]: _12 = Lt(move _13, move _14)"><span class="annotation">@7⦊</span>a &lt; b<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="20:13-20:14: @10[2]: _16 = _6
+20:17-20:18: @10[4]: _17 = _7
+20:13-20:18: @10[5]: _15 = Lt(move _16, move _17)"><span class="annotation">@10⦊</span>b &lt; c<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="23:9-23:17: @15[2]: FakeRead(ForLet, _18)"><span class="annotation">@15⦊</span>somebool<span class="annotation">⦉@15</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="25:13-25:14: @11[6]: _20 = _6
+25:17-25:18: @11[8]: _21 = _5
+25:13-25:18: @11[9]: _19 = Lt(move _20, move _21)"><span class="annotation">@11⦊</span>b &lt; a<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ||</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="27:13-27:14: @14[2]: _23 = _6
+27:17-27:18: @14[4]: _24 = _7
+27:13-27:18: @14[5]: _22 = Lt(move _23, move _24)"><span class="annotation">@14⦊</span>b &lt; c<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="30:9-30:17: @19[2]: FakeRead(ForLet, _25)"><span class="annotation">@19⦊</span>somebool<span class="annotation">⦉@19</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="32:13-32:14: @15[6]: _27 = _5
+32:17-32:18: @15[8]: _28 = _6
+32:13-32:18: @15[9]: _26 = Lt(move _27, move _28)"><span class="annotation">@15⦊</span>a &lt; b<span class="annotation">⦉@15</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        &amp;&amp;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="34:13-34:14: @18[2]: _30 = _6
+34:17-34:18: @18[4]: _31 = _7
+34:13-34:18: @18[5]: _29 = Lt(move _30, move _31)"><span class="annotation">@18⦊</span>b &lt; c<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="37:9-37:17: @23[2]: FakeRead(ForLet, _32)"><span class="annotation">@23⦊</span>somebool<span class="annotation">⦉@23</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        =</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="39:13-39:14: @19[6]: _34 = _6
+39:17-39:18: @19[8]: _35 = _5
+39:13-39:18: @19[9]: _33 = Lt(move _34, move _35)"><span class="annotation">@19⦊</span>b &lt; a<span class="annotation">⦉@19</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        &amp;&amp;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="41:13-41:14: @22[2]: _37 = _6
+41:17-41:18: @22[4]: _38 = _7
+41:13-41:18: @22[5]: _36 = Lt(move _37, move _38)"><span class="annotation">@22⦊</span>b &lt; c<span class="annotation">⦉@22</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="43:2-43:2: @23.Return: return"><span class="annotation">@23⦊</span>‸<span class="annotation">⦉@23</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..dc26c79
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.loop_break_value/loop_break_value.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>loop_break_value.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return"><span class="annotation">@0,1⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">    let result</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">        =</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            loop</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">        {</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            break</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            10</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">            ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">        }</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">    ;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="6:13-11:10: @0.FalseUnwind: falseUnwind -&gt; [real: bb1, cleanup: bb2]
+9:13-9:15: @1[0]: _1 = const 10_i32
+4:9-4:15: @1[1]: FakeRead(ForLet, _1)
+3:11-13:2: @1[2]: _0 = const ()
+13:2-13:2: @1.Return: return">}<span class="annotation">⦉@0,1</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..4b21d3f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_loop/simple_loop.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>simple_loop.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb15]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb14]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 0_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)">    let mut countdown = 0<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="12:9-12:16: @3[6]: _7 = _1
+12:9-12:16: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">        =</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">            10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">        ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="14:9-16:15: @6[0]: _5 = const 10_i32
+13:5-18:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    loop</span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="23:13-23:22: @9[3]: _11 = _5
+23:13-25:14: @9[4]: _10 = Eq(move _11, const 0_i32)
+23:13-25:14: @9[6]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@8,9⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:13-23:22: @9[3]: _11 = _5
+23:13-25:14: @9[4]: _10 = Eq(move _11, const 0_i32)
+23:13-25:14: @9[6]: FakeRead(ForMatchedPlace, _10)">                ==</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="23:13-23:22: @9[3]: _11 = _5
+23:13-25:14: @9[4]: _10 = Eq(move _11, const 0_i32)
+23:13-25:14: @9[6]: FakeRead(ForMatchedPlace, _10)">            0<span class="annotation">⦉@8,9</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="27:13-27:18: @12[0]: _0 = const ()"><span class="annotation">@10,12⦊</span>break<span class="annotation">⦉@10,12</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">            ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="30:9-32:10: @11[3]: _13 = CheckedSub(_5, const 1_i32)"><span class="annotation">@11⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @11[3]: _13 = CheckedSub(_5, const 1_i32)">        -=</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @11[3]: _13 = CheckedSub(_5, const 1_i32)">        1<span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="35:2-35:2: @12.Return: return"><span class="annotation">@10,12⦊</span>‸<span class="annotation">⦉@10,12</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..5ba770e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.simple_match/simple_match.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,190 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>simple_match.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // Initialize test constants in a way that cannot be determined at compile time, to ensure</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from</span></span>
+<span class="line"><span class="code" style="--layer: 0">    // dependent conditions.</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb22]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb21]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 1_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"><span class="annotation">@0,1,2,3⦊</span>is_true = std::env::args().len() == 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb22]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb21]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 1_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)"></span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="7:19-7:35: @0.Call: _4 = args() -&gt; [return: bb1, unwind: bb22]
+7:19-7:35: @1[0]: _3 = &amp;_4
+7:19-7:41: @1.Call: _2 = &lt;Args as ExactSizeIterator&gt;::len(move _3) -&gt; [return: bb2, unwind: bb21]
+7:19-7:46: @2[1]: _1 = Eq(move _2, const 1_usize)
+7:9-7:16: @2[3]: FakeRead(ForLet, _1)
+9:25-9:26: @3[2]: _5 = const 1_i32
+9:9-9:22: @3[3]: FakeRead(ForLet, _5)">    let mut countdown = 1<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="10:8-10:15: @3[6]: _7 = _1
+10:8-10:15: @3[7]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@0,1,2,3⦊</span>is_true<span class="annotation">⦉@0,1,2,3</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="11:9-11:22: @6[0]: _5 = const 0_i32
+10:16-12:6: @6[1]: _6 = const ()"><span class="annotation">@4,6⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:22: @6[0]: _5 = const 0_i32
+10:16-12:6: @6[1]: _6 = const ()">        countdown = 0;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="11:9-11:22: @6[0]: _5 = const 0_i32
+10:16-12:6: @6[1]: _6 = const ()">    }<span class="annotation">⦉@4,6</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="15:9-15:10: @11[2]: _17 = discriminant(_14)"><span class="annotation">@9,10,11⦊</span>for</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:9-15:10: @11[2]: _17 = discriminant(_14)">        _<span class="annotation">⦉@9,10,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    in</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="17:9-17:13: @7[4]: _9 = std::ops::Range::&lt;i32&gt; { start: const 0_i32, end: const 2_i32 }
+17:9-17:13: @7.Call: _8 = &lt;std::ops::Range&lt;i32&gt; as IntoIterator&gt;::into_iter(move _9) -&gt; [return: bb8, unwind: bb22]
+17:9-17:13: @8[1]: FakeRead(ForMatchedPlace, _8)
+17:9-17:13: @8[3]: _10 = move _8"><span class="annotation">@7,8⦊</span>0..2<span class="annotation">⦉@7,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let z</span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        match</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)"><span class="annotation">@13,15,17⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">        {</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">            x</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">            if</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">                x</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">                    &lt;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="22:13-22:22: @15[13]: FakeRead(ForMatchedPlace, _5)
+24:13-24:14: @17[1]: _24 = &amp;_5
+26:17-26:18: @17[4]: _26 = (*_24)
+26:17-28:18: @17[5]: _25 = Lt(move _26, const 1_i32)">                1<span class="annotation">⦉@13,15,17</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">            =&gt;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()"><span class="annotation">@18⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                z = countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                let y = countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                countdown = 10</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">                ;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="31:21-31:30: @18[5]: _27 = _5
+31:17-31:30: @18[6]: _22 = move _27
+33:25-33:34: @18[9]: _28 = _5
+33:21-33:22: @18[10]: FakeRead(ForLet, _28)
+35:17-35:31: @18[11]: _5 = const 10_i32
+30:13-37:14: @18[12]: _21 = const ()">            }<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">            _</span></span>
+<span class="line"><span class="code" style="--layer: 0">            =&gt;</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="40:13-40:15: @16[0]: _21 = const ()"><span class="annotation">@16⦊</span>{}<span class="annotation">⦉@16</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="43:2-43:2: @12.Return: return"><span class="annotation">@12⦊</span>‸<span class="annotation">⦉@12</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..9f99334
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.call.-------.InstrumentCoverage.0.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>try_error_result.call - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 3"><span class="line"><span class="code" style="--layer: 0">fn call(return_error: bool) -&gt; Result&lt;(),()&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="5:8-5:20: @0[1]: _2 = _1
+5:8-5:20: @0[2]: FakeRead(ForMatchedPlace, _2)"><span class="annotation">@0⦊</span>return_error<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="6:13-6:15: @3[1]: _3 = ()
+6:9-6:16: @3[2]: _0 = std::result::Result::&lt;(), ()&gt;::Err(move _3)"><span class="annotation">@1,3⦊</span>Err(())<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="8:12-8:14: @2[1]: _4 = ()
+8:9-8:15: @2[2]: _0 = std::result::Result::&lt;(), ()&gt;::Ok(move _4)"><span class="annotation">@2⦊</span>Ok(())<span class="annotation">⦉@2</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="10:2-10:2: @4.Return: return"><span class="annotation">@4⦊</span>‸<span class="annotation">⦉@4</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..660c303
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.try_error_result/try_error_result.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>try_error_result.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 11"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),()&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="14:21-14:23: @0[1]: _1 = const 10_i32
+13:9-14:18: @0[2]: FakeRead(ForLet, _1)"><span class="annotation">@0,1⦊</span>mut</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="14:21-14:23: @0[1]: _1 = const 10_i32
+13:9-14:18: @0[2]: FakeRead(ForLet, _1)">        countdown = 10<span class="annotation">⦉@0,1</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="17:9-17:10: @4[2]: _12 = discriminant(_9)"><span class="annotation">@2,3,4⦊</span>for</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="17:9-17:10: @4[2]: _12 = discriminant(_9)">        _<span class="annotation">⦉@2,3,4</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    in</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="19:9-19:14: @0[6]: _4 = std::ops::Range::&lt;i32&gt; { start: const 0_i32, end: const 10_i32 }
+19:9-19:14: @0.Call: _3 = &lt;std::ops::Range&lt;i32&gt; as IntoIterator&gt;::into_iter(move _4) -&gt; [return: bb1, unwind: bb32]
+19:9-19:14: @1[1]: FakeRead(ForMatchedPlace, _3)
+19:9-19:14: @1[3]: _5 = move _3"><span class="annotation">@0,1⦊</span>0..10<span class="annotation">⦉@0,1</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="21:9-22:17: @8[12]: _17 = CheckedSub(_1, const 1_i32)"><span class="annotation">@6,8⦊</span>countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="21:9-22:17: @8[12]: _17 = CheckedSub(_1, const 1_i32)">            -= 1<span class="annotation">⦉@6,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="25:13-25:22: @9[3]: _19 = _1
+25:13-25:26: @9[4]: _18 = Lt(move _19, const 5_i32)
+25:13-25:26: @9[6]: FakeRead(ForMatchedPlace, _18)"><span class="annotation">@9⦊</span>countdown &lt; 5<span class="annotation">⦉@9</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code odd" style="--layer: 1" title="27:13-27:41: @12.Call: _22 = call(const true) -&gt; [return: bb13, unwind: bb32]
+27:13-27:42: @13.Call: _21 = &lt;std::result::Result&lt;(), ()&gt; as Try&gt;::into_result(move _22) -&gt; [return: bb14, unwind: bb32]
+27:13-27:42: @14[1]: FakeRead(ForMatchedPlace, _21)
+27:41-27:42: @14[2]: _23 = discriminant(_21)"><span class="annotation">@10,12,13,14⦊</span>call(/*return_error=*/ true)?<span class="annotation">⦉@10,12,13,14</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        else</span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="31:13-31:42: @11.Call: _31 = call(const false) -&gt; [return: bb21, unwind: bb32]
+31:13-31:43: @21.Call: _30 = &lt;std::result::Result&lt;(), ()&gt; as Try&gt;::into_result(move _31) -&gt; [return: bb22, unwind: bb32]
+31:13-31:43: @22[1]: FakeRead(ForMatchedPlace, _30)
+31:42-31:43: @22[2]: _32 = discriminant(_30)"><span class="annotation">@11,21,22⦊</span>call(/*return_error=*/ false)?<span class="annotation">⦉@11,21,22</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="34:8-34:10: @5[9]: _38 = ()
+34:5-34:11: @5[10]: _0 = std::result::Result::&lt;(), ()&gt;::Ok(move _38)"><span class="annotation">@5⦊</span>Ok(())<span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="35:2-35:2: @31.Return: return"><span class="annotation">@31⦊</span>‸<span class="annotation">⦉@31</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..28f1d01
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.various_conditions/various_conditions.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,228 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>various_conditions.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="4:25-4:26: @0[1]: _1 = const 0_u32
+4:9-4:22: @0[2]: FakeRead(ForLet, _1)"><span class="annotation">@0⦊</span>mut countdown = 0<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="5:8-5:12: @0[5]: _3 = const true
+5:8-5:12: @0[6]: FakeRead(ForMatchedPlace, _3)"><span class="annotation">@0⦊</span>true<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="6:9-6:23: @3[0]: _1 = const 10_u32
+5:13-7:6: @3[1]: _2 = const ()"><span class="annotation">@1,3⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="6:9-6:23: @3[0]: _1 = const 10_u32
+5:13-7:6: @3[1]: _2 = const ()">        countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="6:9-6:23: @3[0]: _1 = const 10_u32
+5:13-7:6: @3[1]: _2 = const ()">    }<span class="annotation">⦉@1,3</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    const B: u32 = 100;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="10:9-10:10: @25[0]: FakeRead(ForLet, _4)"><span class="annotation">@25⦊</span>x<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code odd" style="--layer: 1" title="10:16-10:25: @4[5]: _6 = _1
+10:16-10:29: @4[6]: _5 = Gt(move _6, const 7_u32)
+10:16-10:29: @4[8]: FakeRead(ForMatchedPlace, _5)"><span class="annotation">@4⦊</span>countdown &gt; 7<span class="annotation">⦉@4</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="11:9-11:23: @7[0]: _7 = CheckedSub(_1, const 4_u32)"><span class="annotation">@5,7⦊</span>countdown -= 4<span class="annotation">⦉@5,7</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="12:9-12:10: @8[1]: _4 = const B"><span class="annotation">@8⦊</span>B<span class="annotation">⦉@8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="13:15-13:24: @6[2]: _9 = _1
+13:15-13:28: @6[3]: _8 = Gt(move _9, const 2_u32)
+13:15-13:28: @6[5]: FakeRead(ForMatchedPlace, _8)"><span class="annotation">@6⦊</span>countdown &gt; 2<span class="annotation">⦉@6</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="14:12-14:21: @11[5]: _14 = _1
+14:12-14:25: @11[6]: _13 = Lt(move _14, const 1_u32)"><span class="annotation">@9,11⦊</span>countdown &lt; 1<span class="annotation">⦉@9,11</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="14:29-14:38: @18[2]: _16 = _1
+14:29-14:42: @18[3]: _15 = Gt(move _16, const 5_u32)"><span class="annotation">@18⦊</span>countdown &gt; 5<span class="annotation">⦉@18</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="14:46-14:55: @14[2]: _18 = _1
+14:46-14:60: @14[3]: _17 = Ne(move _18, const 9_u32)"><span class="annotation">@14⦊</span>countdown != 9<span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="15:13-15:26: @22[0]: _1 = const 0_u32
+14:61-16:10: @22[1]: _10 = const ()"><span class="annotation">@20,22⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @22[0]: _1 = const 0_u32
+14:61-16:10: @22[1]: _10 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="15:13-15:26: @22[0]: _1 = const 0_u32
+14:61-16:10: @22[1]: _10 = const ()">        }<span class="annotation">⦉@20,22</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="17:9-17:23: @23[2]: _19 = CheckedSub(_1, const 5_u32)"><span class="annotation">@23⦊</span>countdown -= 5<span class="annotation">⦉@23</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="18:9-18:18: @24[1]: _4 = _1"><span class="annotation">@24⦊</span>countdown<span class="annotation">⦉@24</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="20:9-20:15: @10[0]: _0 = const ()"><span class="annotation">@10⦊</span>return<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    };</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="23:25-23:26: @25[3]: _21 = const 0_i32
+23:9-23:22: @25[4]: FakeRead(ForLet, _21)"><span class="annotation">@25⦊</span>mut countdown = 0<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="24:8-24:12: @25[7]: _23 = const true
+24:8-24:12: @25[8]: FakeRead(ForMatchedPlace, _23)"><span class="annotation">@25⦊</span>true<span class="annotation">⦉@25</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code odd" style="--layer: 1" title="25:9-25:23: @28[0]: _21 = const 10_i32
+24:13-26:6: @28[1]: _22 = const ()"><span class="annotation">@26,28⦊</span>{</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @28[0]: _21 = const 10_i32
+24:13-26:6: @28[1]: _22 = const ()">        countdown = 10;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="25:9-25:23: @28[0]: _21 = const 10_i32
+24:13-26:6: @28[1]: _22 = const ()">    }<span class="annotation">⦉@26,28</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="28:8-28:17: @29[5]: _26 = _21
+28:8-28:21: @29[6]: _25 = Gt(move _26, const 7_i32)
+28:8-28:21: @29[8]: FakeRead(ForMatchedPlace, _25)"><span class="annotation">@29⦊</span>countdown &gt; 7<span class="annotation">⦉@29</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="29:9-29:23: @32[0]: _27 = CheckedSub(_21, const 4_i32)"><span class="annotation">@30,32⦊</span>countdown -= 4<span class="annotation">⦉@30,32</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="30:15-30:24: @31[2]: _29 = _21
+30:15-30:28: @31[3]: _28 = Gt(move _29, const 2_i32)
+30:15-30:28: @31[5]: FakeRead(ForMatchedPlace, _28)"><span class="annotation">@31⦊</span>countdown &gt; 2<span class="annotation">⦉@31</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="31:12-31:21: @36[5]: _34 = _21
+31:12-31:25: @36[6]: _33 = Lt(move _34, const 1_i32)"><span class="annotation">@34,36⦊</span>countdown &lt; 1<span class="annotation">⦉@34,36</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="31:29-31:38: @43[2]: _36 = _21
+31:29-31:42: @43[3]: _35 = Gt(move _36, const 5_i32)"><span class="annotation">@43⦊</span>countdown &gt; 5<span class="annotation">⦉@43</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="31:46-31:55: @39[2]: _38 = _21
+31:46-31:60: @39[3]: _37 = Ne(move _38, const 9_i32)"><span class="annotation">@39⦊</span>countdown != 9<span class="annotation">⦉@39</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="32:13-32:26: @47[0]: _21 = const 0_i32
+31:61-33:10: @47[1]: _30 = const ()"><span class="annotation">@45,47⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="32:13-32:26: @47[0]: _21 = const 0_i32
+31:61-33:10: @47[1]: _30 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="32:13-32:26: @47[0]: _21 = const 0_i32
+31:61-33:10: @47[1]: _30 = const ()">        }<span class="annotation">⦉@45,47</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="34:9-34:23: @48[2]: _39 = CheckedSub(_21, const 5_i32)"><span class="annotation">@48⦊</span>countdown -= 5<span class="annotation">⦉@48</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="36:9-36:15: @35[0]: _0 = const ()"><span class="annotation">@35⦊</span>return<span class="annotation">⦉@35</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code odd" style="--layer: 1" title="39:25-39:26: @50[3]: _41 = const 0_i32
+39:9-39:22: @50[4]: FakeRead(ForLet, _41)"><span class="annotation">@50⦊</span>mut countdown = 0<span class="annotation">⦉@50</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code odd" style="--layer: 1" title="40:8-40:12: @50[7]: _43 = const true
+40:8-40:12: @50[8]: FakeRead(ForMatchedPlace, _43)"><span class="annotation">@50⦊</span>true<span class="annotation">⦉@50</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="41:9-41:22: @53[0]: _41 = const 1_i32
+40:13-42:6: @53[1]: _42 = const ()"><span class="annotation">@51,53⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="41:9-41:22: @53[0]: _41 = const 1_i32
+40:13-42:6: @53[1]: _42 = const ()">        countdown = 1;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="41:9-41:22: @53[0]: _41 = const 1_i32
+40:13-42:6: @53[1]: _42 = const ()">    }<span class="annotation">⦉@51,53</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code odd" style="--layer: 1" title="44:9-44:10: @77[0]: FakeRead(ForLet, _44)"><span class="annotation">@77⦊</span>z<span class="annotation">⦉@77</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="44:16-44:25: @54[5]: _46 = _41
+44:16-44:29: @54[6]: _45 = Gt(move _46, const 7_i32)
+44:16-44:29: @54[8]: FakeRead(ForMatchedPlace, _45)"><span class="annotation">@54⦊</span>countdown &gt; 7<span class="annotation">⦉@54</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="45:9-45:23: @57[0]: _47 = CheckedSub(_41, const 4_i32)"><span class="annotation">@55,57⦊</span>countdown -= 4<span class="annotation">⦉@55,57</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="46:15-46:24: @56[2]: _49 = _41
+46:15-46:28: @56[3]: _48 = Gt(move _49, const 2_i32)
+46:15-46:28: @56[5]: FakeRead(ForMatchedPlace, _48)"><span class="annotation">@56⦊</span>countdown &gt; 2<span class="annotation">⦉@56</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="47:12-47:21: @61[5]: _54 = _41
+47:12-47:25: @61[6]: _53 = Lt(move _54, const 1_i32)"><span class="annotation">@59,61⦊</span>countdown &lt; 1<span class="annotation">⦉@59,61</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="47:29-47:38: @68[2]: _56 = _41
+47:29-47:42: @68[3]: _55 = Gt(move _56, const 5_i32)"><span class="annotation">@68⦊</span>countdown &gt; 5<span class="annotation">⦉@68</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="47:46-47:55: @64[2]: _58 = _41
+47:46-47:60: @64[3]: _57 = Ne(move _58, const 9_i32)"><span class="annotation">@64⦊</span>countdown != 9<span class="annotation">⦉@64</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="48:13-48:26: @72[0]: _41 = const 0_i32
+47:61-49:10: @72[1]: _50 = const ()"><span class="annotation">@70,72⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="48:13-48:26: @72[0]: _41 = const 0_i32
+47:61-49:10: @72[1]: _50 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="48:13-48:26: @72[0]: _41 = const 0_i32
+47:61-49:10: @72[1]: _50 = const ()">        }<span class="annotation">⦉@70,72</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="50:9-50:23: @73[2]: _59 = CheckedSub(_41, const 5_i32)"><span class="annotation">@73⦊</span>countdown -= 5<span class="annotation">⦉@73</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        let </span><span><span class="code even" style="--layer: 1" title="52:35-52:44: @60[1]: _61 = _41
+52:13-52:32: @60[2]: FakeRead(ForLet, _61)
+53:18-53:27: @60[9]: _92 = const main::promoted[1]
+53:18-53:27: @60[10]: _67 = &amp;(*_92)
+53:18-53:27: @60[11]: _66 = &amp;(*_67)
+53:18-53:27: @60[12]: _65 = move _66 as &amp;[&amp;str] (Pointer(Unsize))
+53:9-53:29: @60[18]: _73 = ()
+53:9-53:29: @60[19]: FakeRead(ForMatchedPlace, _73)
+53:9-53:29: @60[20]: _91 = const main::promoted[0]
+53:9-53:29: @60[21]: _71 = &amp;(*_91)
+53:9-53:29: @60[22]: _70 = &amp;(*_71)
+53:9-53:29: @60[23]: _69 = move _70 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:9-53:29: @60.Call: _64 = Arguments::new_v1(move _65, move _69) -&gt; [return: bb75, unwind: bb103]
+53:9-53:29: @75.Call: _63 = _print(move _64) -&gt; [return: bb76, unwind: bb103]
+53:9-53:29: @76[5]: _62 = const ()
+54:9-54:15: @76[7]: _0 = const ()"><span class="annotation">@60,75,76⦊</span>should_be_reachable = countdown;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:35-52:44: @60[1]: _61 = _41
+52:13-52:32: @60[2]: FakeRead(ForLet, _61)
+53:18-53:27: @60[9]: _92 = const main::promoted[1]
+53:18-53:27: @60[10]: _67 = &amp;(*_92)
+53:18-53:27: @60[11]: _66 = &amp;(*_67)
+53:18-53:27: @60[12]: _65 = move _66 as &amp;[&amp;str] (Pointer(Unsize))
+53:9-53:29: @60[18]: _73 = ()
+53:9-53:29: @60[19]: FakeRead(ForMatchedPlace, _73)
+53:9-53:29: @60[20]: _91 = const main::promoted[0]
+53:9-53:29: @60[21]: _71 = &amp;(*_91)
+53:9-53:29: @60[22]: _70 = &amp;(*_71)
+53:9-53:29: @60[23]: _69 = move _70 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:9-53:29: @60.Call: _64 = Arguments::new_v1(move _65, move _69) -&gt; [return: bb75, unwind: bb103]
+53:9-53:29: @75.Call: _63 = _print(move _64) -&gt; [return: bb76, unwind: bb103]
+53:9-53:29: @76[5]: _62 = const ()
+54:9-54:15: @76[7]: _0 = const ()">        println!("reached");</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="52:35-52:44: @60[1]: _61 = _41
+52:13-52:32: @60[2]: FakeRead(ForLet, _61)
+53:18-53:27: @60[9]: _92 = const main::promoted[1]
+53:18-53:27: @60[10]: _67 = &amp;(*_92)
+53:18-53:27: @60[11]: _66 = &amp;(*_67)
+53:18-53:27: @60[12]: _65 = move _66 as &amp;[&amp;str] (Pointer(Unsize))
+53:9-53:29: @60[18]: _73 = ()
+53:9-53:29: @60[19]: FakeRead(ForMatchedPlace, _73)
+53:9-53:29: @60[20]: _91 = const main::promoted[0]
+53:9-53:29: @60[21]: _71 = &amp;(*_91)
+53:9-53:29: @60[22]: _70 = &amp;(*_71)
+53:9-53:29: @60[23]: _69 = move _70 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+53:9-53:29: @60.Call: _64 = Arguments::new_v1(move _65, move _69) -&gt; [return: bb75, unwind: bb103]
+53:9-53:29: @75.Call: _63 = _print(move _64) -&gt; [return: bb76, unwind: bb103]
+53:9-53:29: @76[5]: _62 = const ()
+54:9-54:15: @76[7]: _0 = const ()">        return<span class="annotation">⦉@60,75,76</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    };</span></span>
+<span class="line"><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code odd" style="--layer: 1" title="57:9-57:10: @98[0]: FakeRead(ForLet, _74)"><span class="annotation">@98⦊</span>w<span class="annotation">⦉@98</span></span></span><span class="code" style="--layer: 0"> = if </span><span><span class="code even" style="--layer: 1" title="57:16-57:25: @77[5]: _76 = _41
+57:16-57:29: @77[6]: _75 = Gt(move _76, const 7_i32)
+57:16-57:29: @77[8]: FakeRead(ForMatchedPlace, _75)"><span class="annotation">@77⦊</span>countdown &gt; 7<span class="annotation">⦉@77</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="58:9-58:23: @80[0]: _77 = CheckedSub(_41, const 4_i32)"><span class="annotation">@78,80⦊</span>countdown -= 4<span class="annotation">⦉@78,80</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else if </span><span><span class="code even" style="--layer: 1" title="59:15-59:24: @79[2]: _79 = _41
+59:15-59:28: @79[3]: _78 = Gt(move _79, const 2_i32)
+59:15-59:28: @79[5]: FakeRead(ForMatchedPlace, _78)"><span class="annotation">@79⦊</span>countdown &gt; 2<span class="annotation">⦉@79</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if </span><span><span class="code odd" style="--layer: 1" title="60:12-60:21: @84[5]: _84 = _41
+60:12-60:25: @84[6]: _83 = Lt(move _84, const 1_i32)"><span class="annotation">@82,84⦊</span>countdown &lt; 1<span class="annotation">⦉@82,84</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code even" style="--layer: 1" title="60:29-60:38: @91[2]: _86 = _41
+60:29-60:42: @91[3]: _85 = Gt(move _86, const 5_i32)"><span class="annotation">@91⦊</span>countdown &gt; 5<span class="annotation">⦉@91</span></span></span><span class="code" style="--layer: 0"> || </span><span><span class="code odd" style="--layer: 1" title="60:46-60:55: @87[2]: _88 = _41
+60:46-60:60: @87[3]: _87 = Ne(move _88, const 9_i32)"><span class="annotation">@87⦊</span>countdown != 9<span class="annotation">⦉@87</span></span></span><span class="code" style="--layer: 0"> </span><span><span class="code even" style="--layer: 1" title="61:13-61:26: @95[0]: _41 = const 0_i32
+60:61-62:10: @95[1]: _80 = const ()"><span class="annotation">@93,95⦊</span>{</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="61:13-61:26: @95[0]: _41 = const 0_i32
+60:61-62:10: @95[1]: _80 = const ()">            countdown = 0;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="61:13-61:26: @95[0]: _41 = const 0_i32
+60:61-62:10: @95[1]: _80 = const ()">        }<span class="annotation">⦉@93,95</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="63:9-63:23: @96[2]: _89 = CheckedSub(_41, const 5_i32)"><span class="annotation">@96⦊</span>countdown -= 5<span class="annotation">⦉@96</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="65:9-65:15: @83[0]: _0 = const ()"><span class="annotation">@83⦊</span>return<span class="annotation">⦉@83</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    };</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="67:2-67:2: @102.Return: return"><span class="annotation">@102⦊</span>‸<span class="annotation">⦉@102</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html
new file mode 100644
index 0000000..b96789a
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-spanview-deadcode/expected_mir_dump.while_early_return/while_early_return.main.-------.InstrumentCoverage.0.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>while_early_return.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 3"><span class="line"><span class="code" style="--layer: 0">fn main() -&gt; Result&lt;(),u8&gt; {</span></span>
+<span class="line"><span class="code" style="--layer: 0">    let </span><span><span class="code even" style="--layer: 1" title="5:25-5:27: @0[1]: _1 = const 10_i32
+5:9-5:22: @0[2]: FakeRead(ForLet, _1)"><span class="annotation">@0⦊</span>mut countdown = 10<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)"><span class="annotation">@1,2⦊</span>while</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)">        countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)">            &gt;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="7:9-7:18: @2[2]: _5 = _1
+7:9-9:10: @2[3]: _4 = Gt(move _5, const 0_i32)
+7:9-9:10: @2[5]: FakeRead(ForMatchedPlace, _4)">        0<span class="annotation">⦉@1,2</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        if</span></span>
+<span class="line"><span class="code" style="--layer: 0">            </span><span><span class="code even" style="--layer: 1" title="12:13-12:22: @5[3]: _8 = _1
+12:13-14:14: @5[4]: _7 = Lt(move _8, const 5_i32)
+12:13-14:14: @5[6]: FakeRead(ForMatchedPlace, _7)"><span class="annotation">@3,5⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="12:13-12:22: @5[3]: _8 = _1
+12:13-14:14: @5[4]: _7 = Lt(move _8, const 5_i32)
+12:13-14:14: @5[6]: FakeRead(ForMatchedPlace, _7)">                &lt;</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="12:13-12:22: @5[3]: _8 = _1
+12:13-14:14: @5[4]: _7 = Lt(move _8, const 5_i32)
+12:13-14:14: @5[6]: FakeRead(ForMatchedPlace, _7)">            5<span class="annotation">⦉@3,5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        {</span></span>
+<span class="line"><span class="code" style="--layer: 0">            return</span></span>
+<span class="line"><span class="code" style="--layer: 0">                if</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    </span><span><span class="code odd" style="--layer: 1" title="18:21-18:30: @8[2]: _11 = _1
+18:21-20:22: @8[3]: _10 = Gt(move _11, const 8_i32)
+18:21-20:22: @8[5]: FakeRead(ForMatchedPlace, _10)"><span class="annotation">@6,8⦊</span>countdown</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="18:21-18:30: @8[2]: _11 = _1
+18:21-20:22: @8[3]: _10 = Gt(move _11, const 8_i32)
+18:21-20:22: @8[5]: FakeRead(ForMatchedPlace, _10)">                        &gt;</span></span>
+<span class="line"><span class="code odd" style="--layer: 1" title="18:21-18:30: @8[2]: _11 = _1
+18:21-20:22: @8[3]: _10 = Gt(move _11, const 8_i32)
+18:21-20:22: @8[5]: FakeRead(ForMatchedPlace, _10)">                    8<span class="annotation">⦉@6,8</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    </span><span><span class="code even" style="--layer: 1" title="22:24-22:26: @11[1]: _12 = ()
+22:21-22:27: @11[2]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _12)"><span class="annotation">@9,11⦊</span>Ok(())<span class="annotation">⦉@9,11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                else</span></span>
+<span class="line"><span class="code" style="--layer: 0">                {</span></span>
+<span class="line"><span class="code" style="--layer: 0">                    </span><span><span class="code odd" style="--layer: 1" title="26:21-26:27: @10[0]: _0 = std::result::Result::&lt;(), u8&gt;::Err(const 1_u8)"><span class="annotation">@10⦊</span>Err(1)<span class="annotation">⦉@10</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">                }</span></span>
+<span class="line"><span class="code" style="--layer: 0">                ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">        }</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="30:9-32:10: @7[3]: _13 = CheckedSub(_1, const 1_i32)"><span class="annotation">@7⦊</span>countdown</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @7[3]: _13 = CheckedSub(_1, const 1_i32)">            -=</span></span>
+<span class="line"><span class="code even" style="--layer: 1" title="30:9-32:10: @7[3]: _13 = CheckedSub(_1, const 1_i32)">        1<span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">        ;</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="35:8-35:10: @4[4]: _15 = ()
+35:5-35:11: @4[5]: _0 = std::result::Result::&lt;(), u8&gt;::Ok(move _15)"><span class="annotation">@4⦊</span>Ok(())<span class="annotation">⦉@4</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code even" style="--layer: 1" title="36:2-36:2: @14.Return: return"><span class="annotation">@14⦊</span>‸<span class="annotation">⦉@14</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage/closure.rs b/src/test/run-make-fulldeps/coverage/closure.rs
new file mode 100644
index 0000000..66bbbc5
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/closure.rs
@@ -0,0 +1,93 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    // dependent conditions.
+    let is_true = std::env::args().len() == 1;
+    let is_false = ! is_true;
+
+    let mut some_string = Some(String::from("the string content"));
+    println!(
+        "The string or alt: {}"
+        ,
+        some_string
+            .
+            unwrap_or_else
+        (
+            ||
+            {
+                let mut countdown = 0;
+                if is_false {
+                    countdown = 10;
+                }
+                "alt string 1".to_owned()
+            }
+        )
+    );
+
+    some_string = Some(String::from("the string content"));
+    let
+        a
+    =
+        ||
+    {
+        let mut countdown = 0;
+        if is_false {
+            countdown = 10;
+        }
+        "alt string 2".to_owned()
+    };
+    println!(
+        "The string or alt: {}"
+        ,
+        some_string
+            .
+            unwrap_or_else
+        (
+            a
+        )
+    );
+
+    some_string = None;
+    println!(
+        "The string or alt: {}"
+        ,
+        some_string
+            .
+            unwrap_or_else
+        (
+            ||
+            {
+                let mut countdown = 0;
+                if is_false {
+                    countdown = 10;
+                }
+                "alt string 3".to_owned()
+            }
+        )
+    );
+
+    some_string = None;
+    let
+        a
+    =
+        ||
+    {
+        let mut countdown = 0;
+        if is_false {
+            countdown = 10;
+        }
+        "alt string 4".to_owned()
+    };
+    println!(
+        "The string or alt: {}"
+        ,
+        some_string
+            .
+            unwrap_or_else
+        (
+            a
+        )
+    );
+}
diff --git a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir
new file mode 100644
index 0000000..abf8df8
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir
@@ -0,0 +1,3 @@
+# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-*
+
+# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests.
diff --git a/src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk
similarity index 100%
rename from src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk
rename to src/test/run-make-fulldeps/coverage/coverage_tools.mk
diff --git a/src/test/run-make-fulldeps/coverage/drop_trait.rs b/src/test/run-make-fulldeps/coverage/drop_trait.rs
new file mode 100644
index 0000000..d15bfc0
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/drop_trait.rs
@@ -0,0 +1,33 @@
+#![allow(unused_assignments)]
+// expect-exit-status-1
+
+struct Firework {
+    strength: i32,
+}
+
+impl Drop for Firework {
+    fn drop(&mut self) {
+        println!("BOOM times {}!!!", self.strength);
+    }
+}
+
+fn main() -> Result<(),u8> {
+    let _firecracker = Firework { strength: 1 };
+
+    let _tnt = Firework { strength: 100 };
+
+    if true {
+        println!("Exiting with error...");
+        return Err(1);
+    }
+
+    let _ = Firework { strength: 1000 };
+
+    Ok(())
+}
+
+// Expected program output:
+//   Exiting with error...
+//   BOOM times 100!!!
+//   BOOM times 1!!!
+//   Error: 1
diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make-fulldeps/coverage/generics.rs
new file mode 100644
index 0000000..f4e6402
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/generics.rs
@@ -0,0 +1,44 @@
+#![allow(unused_assignments)]
+// expect-exit-status-1
+
+struct Firework<T> where T: Copy + std::fmt::Display {
+    strength: T,
+}
+
+impl<T> Firework<T> where T: Copy + std::fmt::Display {
+    #[inline(always)]
+    fn set_strength(&mut self, new_strength: T) {
+        self.strength = new_strength;
+    }
+}
+
+impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display {
+    #[inline(always)]
+    fn drop(&mut self) {
+        println!("BOOM times {}!!!", self.strength);
+    }
+}
+
+fn main() -> Result<(),u8> {
+    let mut firecracker = Firework { strength: 1 };
+    firecracker.set_strength(2);
+
+    let mut tnt = Firework { strength: 100.1 };
+    tnt.set_strength(200.1);
+    tnt.set_strength(300.3);
+
+    if true {
+        println!("Exiting with error...");
+        return Err(1);
+    }
+
+    let _ = Firework { strength: 1000 };
+
+    Ok(())
+}
+
+// Expected program output:
+//   Exiting with error...
+//   BOOM times 100!!!
+//   BOOM times 1!!!
+//   Error: 1
diff --git a/src/test/run-make-fulldeps/coverage/if.rs b/src/test/run-make-fulldeps/coverage/if.rs
new file mode 100644
index 0000000..8ad5042
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/if.rs
@@ -0,0 +1,28 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    // dependent conditions.
+    let
+    is_true
+    =
+        std::env::args().len()
+    ==
+        1
+    ;
+    let
+        mut
+    countdown
+    =
+        0
+    ;
+    if
+        is_true
+    {
+        countdown
+        =
+            10
+        ;
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/if_else.rs b/src/test/run-make-fulldeps/coverage/if_else.rs
new file mode 100644
index 0000000..3ae4b7a
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/if_else.rs
@@ -0,0 +1,40 @@
+#![allow(unused_assignments)]
+
+fn main() {
+    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    // dependent conditions.
+    let is_true = std::env::args().len() == 1;
+
+    let mut countdown = 0;
+    if
+        is_true
+    {
+        countdown
+        =
+            10
+        ;
+    }
+    else // Note coverage region difference without semicolon
+    {
+        countdown
+        =
+            100
+    }
+
+    if
+        is_true
+    {
+        countdown
+        =
+            10
+        ;
+    }
+    else
+    {
+        countdown
+        =
+            100
+        ;
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/inner_items.rs b/src/test/run-make-fulldeps/coverage/inner_items.rs
new file mode 100644
index 0000000..66e7651
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/inner_items.rs
@@ -0,0 +1,57 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    // dependent conditions.
+    let is_true = std::env::args().len() == 1;
+
+    let mut countdown = 0;
+    if is_true {
+        countdown = 10;
+    }
+
+    mod in_mod {
+        const IN_MOD_CONST: u32 = 1000;
+    }
+
+    fn in_func(a: u32) {
+        let b = 1;
+        let c = a + b;
+        println!("c = {}", c)
+    }
+
+    struct InStruct {
+        in_struct_field: u32,
+    }
+
+    const IN_CONST: u32 = 1234;
+
+    trait InTrait {
+        fn trait_func(&mut self, incr: u32);
+
+        fn default_trait_func(&mut self) {
+            in_func(IN_CONST);
+            self.trait_func(IN_CONST);
+        }
+    }
+
+    impl InTrait for InStruct {
+        fn trait_func(&mut self, incr: u32) {
+            self.in_struct_field += incr;
+            in_func(self.in_struct_field);
+        }
+    }
+
+    type InType = String;
+
+    if is_true {
+        in_func(countdown);
+    }
+
+    let mut val = InStruct {
+        in_struct_field: 101,
+    };
+
+    val.default_trait_func();
+}
diff --git a/src/test/run-make-fulldeps/coverage/lazy_boolean.rs b/src/test/run-make-fulldeps/coverage/lazy_boolean.rs
new file mode 100644
index 0000000..1d83eb3
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/lazy_boolean.rs
@@ -0,0 +1,43 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    // dependent conditions.
+    let is_true = std::env::args().len() == 1;
+
+    let (mut a, mut b, mut c) = (0, 0, 0);
+    if is_true {
+        a = 1;
+        b = 10;
+        c = 100;
+    }
+    let
+        somebool
+        =
+            a < b
+        ||
+            b < c
+    ;
+    let
+        somebool
+        =
+            b < a
+        ||
+            b < c
+    ;
+    let
+        somebool
+        =
+            a < b
+        &&
+            b < c
+    ;
+    let
+        somebool
+        =
+            b < a
+        &&
+            b < c
+    ;
+}
diff --git a/src/test/run-make-fulldeps/coverage/loop_break_value.rs b/src/test/run-make-fulldeps/coverage/loop_break_value.rs
new file mode 100644
index 0000000..ba66d13
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/loop_break_value.rs
@@ -0,0 +1,13 @@
+#![allow(unused_assignments)]
+
+fn main() {
+    let result
+        =
+            loop
+        {
+            break
+            10
+            ;
+        }
+    ;
+}
diff --git a/src/test/run-make-fulldeps/coverage/simple_loop.rs b/src/test/run-make-fulldeps/coverage/simple_loop.rs
new file mode 100644
index 0000000..6f7f234
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/simple_loop.rs
@@ -0,0 +1,35 @@
+#![allow(unused_assignments)]
+
+fn main() {
+    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    // dependent conditions.
+    let is_true = std::env::args().len() == 1;
+
+    let mut countdown = 0;
+
+    if
+        is_true
+    {
+        countdown
+        =
+            10
+        ;
+    }
+
+    loop
+    {
+        if
+            countdown
+                ==
+            0
+        {
+            break
+            ;
+        }
+        countdown
+        -=
+        1
+        ;
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/simple_match.rs b/src/test/run-make-fulldeps/coverage/simple_match.rs
new file mode 100644
index 0000000..c9a24f7
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/simple_match.rs
@@ -0,0 +1,43 @@
+#![allow(unused_assignments)]
+
+fn main() {
+    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    // dependent conditions.
+    let is_true = std::env::args().len() == 1;
+
+    let mut countdown = 1;
+    if is_true {
+        countdown = 0;
+    }
+
+    for
+        _
+    in
+        0..2
+    {
+        let z
+        ;
+        match
+            countdown
+        {
+            x
+            if
+                x
+                    <
+                1
+            =>
+            {
+                z = countdown
+                ;
+                let y = countdown
+                ;
+                countdown = 10
+                ;
+            }
+            _
+            =>
+            {}
+        }
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/try_error_result.rs b/src/test/run-make-fulldeps/coverage/try_error_result.rs
new file mode 100644
index 0000000..3a8f30e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/try_error_result.rs
@@ -0,0 +1,35 @@
+#![allow(unused_assignments)]
+// expect-exit-status-1
+
+fn call(return_error: bool) -> Result<(),()> {
+    if return_error {
+        Err(())
+    } else {
+        Ok(())
+    }
+}
+
+fn main() -> Result<(),()> {
+    let mut
+        countdown = 10
+    ;
+    for
+        _
+    in
+        0..10
+    {
+        countdown
+            -= 1
+        ;
+        if
+            countdown < 5
+        {
+            call(/*return_error=*/ true)?;
+        }
+        else
+        {
+            call(/*return_error=*/ false)?;
+        }
+    }
+    Ok(())
+}
diff --git a/src/test/run-make-fulldeps/coverage/various_conditions.rs b/src/test/run-make-fulldeps/coverage/various_conditions.rs
new file mode 100644
index 0000000..da206e2
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/various_conditions.rs
@@ -0,0 +1,67 @@
+#![allow(unused_assignments, unused_variables)]
+
+fn main() {
+    let mut countdown = 0;
+    if true {
+        countdown = 10;
+    }
+
+    const B: u32 = 100;
+    let x = if countdown > 7 {
+        countdown -= 4;
+        B
+    } else if countdown > 2 {
+        if countdown < 1 || countdown > 5 || countdown != 9 {
+            countdown = 0;
+        }
+        countdown -= 5;
+        countdown
+    } else {
+        return;
+    };
+
+    let mut countdown = 0;
+    if true {
+        countdown = 10;
+    }
+
+    if countdown > 7 {
+        countdown -= 4;
+    } else if countdown > 2 {
+        if countdown < 1 || countdown > 5 || countdown != 9 {
+            countdown = 0;
+        }
+        countdown -= 5;
+    } else {
+        return;
+    }
+
+    let mut countdown = 0;
+    if true {
+        countdown = 1;
+    }
+
+    let z = if countdown > 7 {
+        countdown -= 4;
+    } else if countdown > 2 {
+        if countdown < 1 || countdown > 5 || countdown != 9 {
+            countdown = 0;
+        }
+        countdown -= 5;
+    } else {
+        let should_be_reachable = countdown;
+        println!("reached");
+        return;
+    };
+
+    let w = if countdown > 7 {
+        countdown -= 4;
+    } else if countdown > 2 {
+        if countdown < 1 || countdown > 5 || countdown != 9 {
+            countdown = 0;
+        }
+        countdown -= 5;
+    } else {
+        return;
+    };
+}
diff --git a/src/test/run-make-fulldeps/coverage/while_early_return.rs b/src/test/run-make-fulldeps/coverage/while_early_return.rs
new file mode 100644
index 0000000..14ba362
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/while_early_return.rs
@@ -0,0 +1,47 @@
+#![allow(unused_assignments)]
+// expect-exit-status-1
+
+fn main() -> Result<(),u8> {
+    let mut countdown = 10;
+    while
+        countdown
+            >
+        0
+    {
+        if
+            countdown
+                <
+            5
+        {
+            return
+                if
+                    countdown
+                        >
+                    8
+                {
+                    Ok(())
+                }
+                else
+                {
+                    Err(1)
+                }
+                ;
+        }
+        countdown
+            -=
+        1
+        ;
+    }
+    Ok(())
+}
+
+// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and
+// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux
+// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program
+// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical
+// to the coverage test for early returns, but this is a limitation that should be fixed.
+//
+// FIXME(richkadel): Consider creating a new tests for coverage when calling `std::process::exit()`,
+// move the `ISSUE` comment to that test, and implement a new test directive that supports skipping
+// coverage tests when targeting specific platforms (at least skipping Windows, or MSVC if the
+// problem exists on MSVC only).
diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index dd49ca6..0e1bef6 100644
--- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
+++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
@@ -3,7 +3,6 @@
 extern crate rustc_codegen_ssa;
 extern crate rustc_errors;
 extern crate rustc_middle;
-#[macro_use]
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_hir;
@@ -12,17 +11,19 @@
 extern crate rustc_symbol_mangling;
 extern crate rustc_target;
 
+use rustc_codegen_ssa::back::linker::LinkerInfo;
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::owning_ref::OwningRef;
+use rustc_codegen_ssa::{CodegenResults, CrateInfo};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::MetadataRef;
 use rustc_errors::ErrorReported;
 use rustc_middle::dep_graph::DepGraph;
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
-use rustc_span::symbol::Symbol;
 use rustc_target::spec::Target;
 use std::any::Any;
 use std::path::Path;
@@ -31,14 +32,11 @@
 
 impl MetadataLoader for NoLlvmMetadataLoader {
     fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
-        let buf =
-            std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?;
-        let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf);
-        Ok(rustc_erase_owner!(buf.map_owner_box()))
+        unreachable!("some_crate.rs shouldn't depend on any external crates");
     }
 
     fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
-        self.get_rlib_metadata(target, filename)
+        unreachable!("some_crate.rs shouldn't depend on any external crates");
     }
 }
 
@@ -49,53 +47,49 @@
         Box::new(NoLlvmMetadataLoader)
     }
 
-    fn provide(&self, providers: &mut Providers) {
-        rustc_symbol_mangling::provide(providers);
-
-        providers.supported_target_features = |tcx, _cnum| {
-            Default::default() // Just a dummy
-        };
-        providers.is_reachable_non_generic = |_tcx, _defid| true;
-        providers.exported_symbols = |_tcx, _crate| &[];
-    }
-
-    fn provide_extern(&self, providers: &mut Providers) {
-        providers.is_reachable_non_generic = |_tcx, _defid| true;
-    }
+    fn provide(&self, providers: &mut Providers) {}
+    fn provide_extern(&self, providers: &mut Providers) {}
 
     fn codegen_crate<'a, 'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        _metadata: EncodedMetadata,
+        metadata: EncodedMetadata,
         _need_metadata_module: bool,
     ) -> Box<dyn Any> {
         use rustc_hir::def_id::LOCAL_CRATE;
 
-        Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol)
+        Box::new(CodegenResults {
+            crate_name: tcx.crate_name(LOCAL_CRATE),
+            modules: vec![],
+            allocator_module: None,
+            metadata_module: None,
+            metadata,
+            windows_subsystem: None,
+            linker_info: LinkerInfo::new(tcx),
+            crate_info: CrateInfo::new(tcx),
+        })
     }
 
     fn join_codegen(
         &self,
         ongoing_codegen: Box<dyn Any>,
         _sess: &Session,
-        _dep_graph: &DepGraph,
-    ) -> Result<Box<dyn Any>, ErrorReported> {
-        let crate_name = ongoing_codegen
-            .downcast::<Symbol>()
-            .expect("in join_codegen: ongoing_codegen is not a Symbol");
-        Ok(crate_name)
+    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
+        let codegen_results = ongoing_codegen
+            .downcast::<CodegenResults>()
+            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
+        Ok((*codegen_results, FxHashMap::default()))
     }
 
     fn link(
         &self,
         sess: &Session,
-        codegen_results: Box<dyn Any>,
+        codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported> {
         use rustc_session::{config::CrateType, output::out_filename};
         use std::io::Write;
-        let crate_name =
-            codegen_results.downcast::<Symbol>().expect("in link: codegen_results is not a Symbol");
+        let crate_name = codegen_results.crate_name;
         for &crate_type in sess.opts.crate_types.iter() {
             if crate_type != CrateType::Rlib {
                 sess.fatal(&format!("Crate type is {:?}", crate_type));
diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile
deleted file mode 100644
index cb081fb..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile
+++ /dev/null
@@ -1,81 +0,0 @@
-# needs-profiler-support
-# ignore-windows-gnu
-
-# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
-# properly. Since we only have GCC on the CI ignore the test for now.
-
-# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
-# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
-# See ../instrument-coverage/coverage_tools.mk for more information.
-
--include ../instrument-coverage/coverage_tools.mk
-
-BASEDIR=../instrument-coverage-cov-reports-base
-SOURCEDIR=../instrument-coverage
-
-all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
-
-# Ensure there are no `expected` results for tests that may have been removed or renamed
-.PHONY: clear_expected_if_blessed
-clear_expected_if_blessed:
-ifdef RUSTC_BLESS_TEST
-	rm -f expected_export_coverage.*.json
-	rm -f typical_show_coverage.*.txt
-endif
-
--include clear_expected_if_blessed
-
-%: $(SOURCEDIR)/%.rs
-	# Compile the test program with "experimental" coverage instrumentation and generate relevant MIR.
-	#
-	# FIXME(richkadel):  `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are
-	# satisfied with the branch-level instrumentation.
-	$(RUSTC) $(SOURCEDIR)/$@.rs \
-			-Zexperimental-coverage \
-			-Clink-dead-code=$(LINK_DEAD_CODE)
-
-	# Run it in order to generate some profiling data,
-	# with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
-	# output the coverage stats for this run.
-	LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \
-			$(call RUN,$@)
-
-	# Postprocess the profiling data so it can be used by the llvm-cov tool
-	"$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
-			"$(TMPDIR)"/$@.profraw \
-			-o "$(TMPDIR)"/$@.profdata
-
-	# Generate a coverage report using `llvm-cov show`. The output ordering
-	# can be non-deterministic, so ignore the return status. If the test fails
-	# when comparing the JSON `export`, the `show` output may be useful when
-	# debugging.
-	"$(LLVM_BIN_DIR)"/llvm-cov show \
-			--Xdemangler="$(RUST_DEMANGLER)" \
-			--show-line-counts-or-regions \
-			--instr-profile="$(TMPDIR)"/$@.profdata \
-			$(call BIN,"$(TMPDIR)"/$@) \
-		> "$(TMPDIR)"/actual_show_coverage.$@.txt
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/actual_show_coverage.$@.txt typical_show_coverage.$@.txt
-else
-	# Compare the show coverage output (`--bless` refreshes `typical` files)
-	$(DIFF) typical_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \
-		>&2 echo 'diff failed for `llvm-cov show` on $@ (might not be an error)'
-endif
-
-	# Generate a coverage report in JSON, using `llvm-cov export`, and fail if
-	# there are differences from the expected output.
-	"$(LLVM_BIN_DIR)"/llvm-cov export \
-			--summary-only \
-			--instr-profile="$(TMPDIR)"/$@.profdata \
-			$(call BIN,"$(TMPDIR)"/$@) \
-		| "$(PYTHON)" $(BASEDIR)/prettify_json.py \
-		> "$(TMPDIR)"/actual_export_coverage.$@.json
-
-ifdef RUSTC_BLESS_TEST
-	cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json
-else
-	# Check that exported JSON coverage data matches what we expect (`--bless` refreshes `expected`)
-	$(DIFF) expected_export_coverage.$@.json "$(TMPDIR)"/actual_export_coverage.$@.json
-endif
diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json
deleted file mode 100644
index b9041eb..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
-  "data": [
-    {
-      "files": [
-        {
-          "filename": "../instrument-coverage/coverage_of_if_else.rs",
-          "summary": {
-            "functions": {
-              "count": 1,
-              "covered": 1,
-              "percent": 100
-            },
-            "instantiations": {
-              "count": 1,
-              "covered": 1,
-              "percent": 100
-            },
-            "lines": {
-              "count": 46,
-              "covered": 19,
-              "percent": 41.30434782608695
-            },
-            "regions": {
-              "count": 75,
-              "covered": 23,
-              "notcovered": 52,
-              "percent": 30.666666666666664
-            }
-          }
-        }
-      ],
-      "totals": {
-        "functions": {
-          "count": 1,
-          "covered": 1,
-          "percent": 100
-        },
-        "instantiations": {
-          "count": 1,
-          "covered": 1,
-          "percent": 100
-        },
-        "lines": {
-          "count": 46,
-          "covered": 19,
-          "percent": 41.30434782608695
-        },
-        "regions": {
-          "count": 75,
-          "covered": 23,
-          "notcovered": 52,
-          "percent": 30.666666666666664
-        }
-      }
-    }
-  ],
-  "type": "llvm.coverage.json.export",
-  "version": "2.0.1"
-}
diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt
deleted file mode 100644
index 0c71155..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt
+++ /dev/null
@@ -1,64 +0,0 @@
-    1|       |#![allow(unused_assignments)]
-    2|       |
-    3|       |fn main() {
-    4|       |    let mut countdown = 0;
-    5|      2|    if true {
-                     ^1
-    6|      2|        countdown = 10;
-    7|      2|    }
-    8|       |
-    9|      2|    if countdown > 7 {
-                     ^1
-   10|      2|        countdown -= 4;
-                      ^1
-   11|      2|    } else if countdown > 2 {
-                         ^0 ^0
-   12|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
-   13|      0|            countdown = 0;
-   14|      0|        }
-   15|      0|        countdown -= 5;
-   16|      0|    } else {
-   17|      0|        return;
-   18|      0|    }
-   19|      0|
-   20|      0|    let mut countdown = 0;
-   21|      2|    if true {
-                     ^1
-   22|      2|        countdown = 10;
-   23|      2|    }
-   24|      0|
-   25|      2|    if countdown > 7 {
-                     ^1
-   26|      2|        countdown -= 4;
-                      ^1
-   27|      2|    } else if countdown > 2 {
-                         ^0 ^0
-   28|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
-   29|      0|            countdown = 0;
-   30|      0|        }
-   31|      0|        countdown -= 5;
-   32|      0|    } else {
-   33|      0|        return;
-   34|      0|    }
-   35|      0|
-   36|      0|    let mut countdown = 0;
-   37|      2|    if true {
-                     ^1
-   38|      2|        countdown = 10;
-   39|      2|    }
-   40|      0|
-   41|      2|    if countdown > 7 {
-                     ^1
-   42|      2|        countdown -= 4;
-                      ^1
-   43|      2|    } else if countdown > 2 {
-                         ^0 ^0
-   44|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
-   45|      0|            countdown = 0;
-   46|      0|        }
-   47|      0|        countdown -= 5;
-   48|      0|    } else {
-   49|      0|        return;
-   50|      0|    }
-   51|      1|}
-
diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile
deleted file mode 100644
index ab826d0..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# needs-profiler-support
-# ignore-msvc
-# ignore-windows-gnu
-
-# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
-# properly. Since we only have GCC on the CI ignore the test for now.
-
-# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038
-LINK_DEAD_CODE=yes
-
--include ../instrument-coverage-cov-reports-base/Makefile
-
-# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
-# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
-# See ../instrument-coverage/coverage_tools.mk for more information.
diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json
deleted file mode 100644
index b9041eb..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
-  "data": [
-    {
-      "files": [
-        {
-          "filename": "../instrument-coverage/coverage_of_if_else.rs",
-          "summary": {
-            "functions": {
-              "count": 1,
-              "covered": 1,
-              "percent": 100
-            },
-            "instantiations": {
-              "count": 1,
-              "covered": 1,
-              "percent": 100
-            },
-            "lines": {
-              "count": 46,
-              "covered": 19,
-              "percent": 41.30434782608695
-            },
-            "regions": {
-              "count": 75,
-              "covered": 23,
-              "notcovered": 52,
-              "percent": 30.666666666666664
-            }
-          }
-        }
-      ],
-      "totals": {
-        "functions": {
-          "count": 1,
-          "covered": 1,
-          "percent": 100
-        },
-        "instantiations": {
-          "count": 1,
-          "covered": 1,
-          "percent": 100
-        },
-        "lines": {
-          "count": 46,
-          "covered": 19,
-          "percent": 41.30434782608695
-        },
-        "regions": {
-          "count": 75,
-          "covered": 23,
-          "notcovered": 52,
-          "percent": 30.666666666666664
-        }
-      }
-    }
-  ],
-  "type": "llvm.coverage.json.export",
-  "version": "2.0.1"
-}
diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt
deleted file mode 100644
index 0c71155..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt
+++ /dev/null
@@ -1,64 +0,0 @@
-    1|       |#![allow(unused_assignments)]
-    2|       |
-    3|       |fn main() {
-    4|       |    let mut countdown = 0;
-    5|      2|    if true {
-                     ^1
-    6|      2|        countdown = 10;
-    7|      2|    }
-    8|       |
-    9|      2|    if countdown > 7 {
-                     ^1
-   10|      2|        countdown -= 4;
-                      ^1
-   11|      2|    } else if countdown > 2 {
-                         ^0 ^0
-   12|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
-   13|      0|            countdown = 0;
-   14|      0|        }
-   15|      0|        countdown -= 5;
-   16|      0|    } else {
-   17|      0|        return;
-   18|      0|    }
-   19|      0|
-   20|      0|    let mut countdown = 0;
-   21|      2|    if true {
-                     ^1
-   22|      2|        countdown = 10;
-   23|      2|    }
-   24|      0|
-   25|      2|    if countdown > 7 {
-                     ^1
-   26|      2|        countdown -= 4;
-                      ^1
-   27|      2|    } else if countdown > 2 {
-                         ^0 ^0
-   28|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
-   29|      0|            countdown = 0;
-   30|      0|        }
-   31|      0|        countdown -= 5;
-   32|      0|    } else {
-   33|      0|        return;
-   34|      0|    }
-   35|      0|
-   36|      0|    let mut countdown = 0;
-   37|      2|    if true {
-                     ^1
-   38|      2|        countdown = 10;
-   39|      2|    }
-   40|      0|
-   41|      2|    if countdown > 7 {
-                     ^1
-   42|      2|        countdown -= 4;
-                      ^1
-   43|      2|    } else if countdown > 2 {
-                         ^0 ^0
-   44|      0|        if countdown < 1 || countdown > 5 || countdown != 9 {
-   45|      0|            countdown = 0;
-   46|      0|        }
-   47|      0|        countdown -= 5;
-   48|      0|    } else {
-   49|      0|        return;
-   50|      0|    }
-   51|      1|}
-
diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile
deleted file mode 100644
index f623248..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile
+++ /dev/null
@@ -1,65 +0,0 @@
-# needs-profiler-support
-
-# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
-# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
-# See ../instrument-coverage/coverage_tools.mk for more information.
-
--include ../instrument-coverage/coverage_tools.mk
-
-BASEDIR=../instrument-coverage-llvm-ir-base
-
-ifeq ($(UNAME),Darwin)
-	INSTR_PROF_DATA_SUFFIX=,regular,live_support
-	DATA_SECTION_PREFIX=__DATA,
-	LLVM_COV_SECTION_PREFIX=__LLVM_COV,
-else
-	INSTR_PROF_DATA_SUFFIX=
-	DATA_SECTION_PREFIX=
-	LLVM_COV_SECTION_PREFIX=
-endif
-
-ifeq ($(LINK_DEAD_CODE),yes)
-	DEFINE_INTERNAL=define hidden
-else
-	DEFINE_INTERNAL=define internal
-endif
-
-ifdef IS_WINDOWS
-	LLVM_FILECHECK_OPTIONS=\
-		-check-prefixes=CHECK,WINDOWS \
-		-DPRIVATE_GLOBAL='internal global' \
-		-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
-		-DINSTR_PROF_DATA='.lprfd$$M' \
-		-DINSTR_PROF_NAME='.lprfn$$M' \
-		-DINSTR_PROF_CNTS='.lprfc$$M' \
-		-DINSTR_PROF_VALS='.lprfv$$M' \
-		-DINSTR_PROF_VNODES='.lprfnd$$M' \
-		-DINSTR_PROF_COVMAP='.lcovmap$$M' \
-		-DINSTR_PROF_ORDERFILE='.lorderfile$$M'
-else
-	LLVM_FILECHECK_OPTIONS=\
-		-check-prefixes=CHECK \
-		-DPRIVATE_GLOBAL='private global' \
-		-DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \
-		-DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \
-		-DINSTR_PROF_NAME='$(DATA_SECTION_PREFIX)__llvm_prf_names' \
-		-DINSTR_PROF_CNTS='$(DATA_SECTION_PREFIX)__llvm_prf_cnts' \
-		-DINSTR_PROF_VALS='$(DATA_SECTION_PREFIX)__llvm_prf_vals' \
-		-DINSTR_PROF_VNODES='$(DATA_SECTION_PREFIX)__llvm_prf_vnds' \
-		-DINSTR_PROF_COVMAP='$(LLVM_COV_SECTION_PREFIX)__llvm_covmap' \
-		-DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile'
-endif
-
-all:
-	# Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR
-	#
-	# Note: `-Clink-dead-code=no` disables the option, needed because the option is automatically
-	# enabled for some platforms, but not for Windows MSVC (due to Issue #76038). The state of this
-	# option affects the generated MIR and coverage, so it is enabled for tests to ensure the
-	# tests results are the same across platforms.
-	$(RUSTC) $(BASEDIR)/testprog.rs \
-			-Zinstrument-coverage \
-			-Clink-dead-code=$(LINK_DEAD_CODE) \
-			--emit=llvm-ir
-
-	cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS)
diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile
deleted file mode 100644
index ba2126a..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# needs-profiler-support
-# ignore-msvc
-
-# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038
-LINK_DEAD_CODE=yes
-
--include ../instrument-coverage-llvm-ir-base/Makefile
-
-# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
-# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
-# See ../instrument-coverage/coverage_tools.mk for more information.
\ No newline at end of file
diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile
deleted file mode 100644
index 5cd4259..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-# needs-profiler-support
-
-# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
-# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
-# See ../instrument-coverage/coverage_tools.mk for more information.
-
--include ../instrument-coverage/coverage_tools.mk
-
-SOURCEDIR=../instrument-coverage
-
-all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
-
-# Ensure there are no `expected` results for tests that may have been removed or renamed
-.PHONY: clear_expected_if_blessed
-clear_expected_if_blessed:
-ifdef RUSTC_BLESS_TEST
-	rm -rf expected_mir_dump.*/
-endif
-
--include clear_expected_if_blessed
-
-%: $(SOURCEDIR)/%.rs
-	# Compile the test program with "experimental" coverage instrumentation and generate relevant MIR.
-	#
-	# FIXME(richkadel): `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are
-	# satisfied with the branch-level instrumentation.
-	$(RUSTC) $(SOURCEDIR)/$@.rs \
-			-Zexperimental-coverage \
-			-Clink-dead-code=$(LINK_DEAD_CODE) \
-			-Zdump-mir=InstrumentCoverage \
-			-Zdump-mir-dir="$(TMPDIR)"/mir_dump.$@
-
-ifdef RUSTC_BLESS_TEST
-	mkdir -p expected_mir_dump.$@
-	cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html expected_mir_dump.$@/
-else
-	# Check that the selected `mir_dump` files match what we expect (`--bless` refreshes `expected`)
-	mkdir -p "$(TMPDIR)"/actual_mir_dump.$@
-	rm -f "$(TMPDIR)"/actual_mir_dump.$@/*
-	cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html "$(TMPDIR)"/actual_mir_dump.$@/
-	$(DIFF) -r expected_mir_dump.$@/ "$(TMPDIR)"/actual_mir_dump.$@/
-endif
diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html
deleted file mode 100644
index 1ea9aba..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html
+++ /dev/null
@@ -1,808 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
-    .line {
-        counter-increment: line;
-    }
-    .line:before {
-        content: counter(line) ": ";
-        font-family: Menlo, Monaco, monospace;
-        font-style: italic;
-        width: 3.8em;
-        display: inline-block;
-        text-align: right;
-        filter: opacity(50%);
-        -webkit-user-select: none;
-    }
-    .code {
-        color: #dddddd;
-        background-color: #222222;
-        font-family: Menlo, Monaco, monospace;
-        line-height: 1.4em;
-        border-bottom: 2px solid #222222;
-        white-space: pre;
-        display: inline-block;
-    }
-    .odd {
-        background-color: #55bbff;
-        color: #223311;
-    }
-    .even {
-        background-color: #ee7756;
-        color: #551133;
-    }
-    .code {
-        --index: calc(var(--layer) - 1);
-        padding-top: calc(var(--index) * 0.15em);
-        filter:
-            hue-rotate(calc(var(--index) * 25deg))
-            saturate(calc(100% - (var(--index) * 2%)))
-            brightness(calc(100% - (var(--index) * 1.5%)));
-    }
-    .annotation {
-        color: #4444ff;
-        font-family: monospace;
-        font-style: italic;
-        display: none;
-        -webkit-user-select: none;
-    }
-    body:active .annotation {
-        /* requires holding mouse down anywhere on the page */
-        display: inline-block;
-    }
-    span:hover .annotation {
-        /* requires hover over a span ONLY on its first line */
-        display: inline-block;
-    }
-    </style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
-<span class="line"><span class="code" style="--layer: 0">    let mut countdown = 0;</span></span>
-<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: FalseEdge: falseEdge -&gt; [real: bb4, imaginary: bb3]"><span class="annotation">2⦊</span></span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    6:9-6:23: Assign: _1 = const 10_i32
-    5:13-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"><span class="annotation">4⦊</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"><span class="annotation">3⦊</span>if </span><span class="code even" style="--layer: 4" title="bb0: ../instrument-coverage/coverage_of_if_else.rs:5:8: 5:12:
-    4:9-4:22: StorageLive: StorageLive(_1)
-    4:25-4:26: Assign: _1 = const 0_i32
-    4:9-4:22: FakeRead: FakeRead(ForLet, _1)
-    5:5-7:6: StorageLive: StorageLive(_2)
-    5:8-5:12: StorageLive: StorageLive(_3)
-    5:8-5:12: Assign: _3 = const true
-    5:8-5:12: FakeRead: FakeRead(ForMatchedPlace, _3)
-    5:5-7:6: SwitchInt: switchInt(_3) -&gt; [false: bb3, otherwise: bb2]"><span class="annotation">0⦊</span>true<span class="annotation">⦉0</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5">        countdown = 10;</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5">    }<span class="annotation">⦉3</span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    6:9-6:23: Assign: _1 = const 10_i32
-    5:13-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"><span class="annotation">⦉4</span></span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: FalseEdge: falseEdge -&gt; [real: bb4, imaginary: bb3]"><span class="annotation">⦉2</span></span></span><span class="code" style="--layer: 0"></span></span>
-<span class="line"><span class="code" style="--layer: 0"></span></span>
-<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    9:5-18:6: FalseEdge: falseEdge -&gt; [real: bb8, imaginary: bb7]"><span class="annotation">6⦊</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    10:9-10:23: Assign: _1 = move (_7.0: i32)
-    9:22-11:6: Assign: _4 = const ()
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">9⦊</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">25⦊</span>if </span><span class="code even" style="--layer: 4" title="bb5: ../instrument-coverage/coverage_of_if_else.rs:9:8: 9:21:
-    7:5-7:6: StorageDead: StorageDead(_3)
-    7:5-7:6: StorageDead: StorageDead(_2)
-    9:5-18:6: StorageLive: StorageLive(_4)
-    9:8-9:21: StorageLive: StorageLive(_5)
-    9:8-9:17: StorageLive: StorageLive(_6)
-    9:8-9:17: Assign: _6 = _1
-    9:8-9:21: Assign: _5 = Gt(move _6, const 7_i32)
-    9:20-9:21: StorageDead: StorageDead(_6)
-    9:8-9:21: FakeRead: FakeRead(ForMatchedPlace, _5)
-    9:5-18:6: SwitchInt: switchInt(_5) -&gt; [false: bb7, otherwise: bb6]"><span class="annotation">5⦊</span>countdown &gt; 7<span class="annotation">⦉5</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28">        </span><span class="code odd" style="--layer: 4" title="bb8: ../instrument-coverage/coverage_of_if_else.rs:10:9: 10:23:
-    10:9-10:23: Assign: _7 = CheckedSub(_1, const 4_i32)
-    10:9-10:23: Assert: assert(!move (_7.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 4_i32) -&gt; [success: bb9, unwind: bb1]"><span class="annotation">8⦊</span>countdown -= 4<span class="annotation">⦉8</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28">;</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28">    } else </span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">10⦊</span>if </span><span class="code even" style="--layer: 5" title="bb7: ../instrument-coverage/coverage_of_if_else.rs:11:15: 11:28:
-    11:15-11:28: StorageLive: StorageLive(_8)
-    11:15-11:24: StorageLive: StorageLive(_9)
-    11:15-11:24: Assign: _9 = _1
-    11:15-11:28: Assign: _8 = Gt(move _9, const 2_i32)
-    11:27-11:28: StorageDead: StorageDead(_9)
-    11:15-11:28: FakeRead: FakeRead(ForMatchedPlace, _8)
-    11:12-18:6: SwitchInt: switchInt(_8) -&gt; [false: bb11, otherwise: bb10]"><span class="annotation">7⦊</span>countdown &gt; 2<span class="annotation">⦉7</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">        </span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">22⦊</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    13:13-13:26: Assign: _1 = const 0_i32
-    12:61-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">23⦊</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"><span class="annotation">21⦊</span>if </span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const false
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">14⦊</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:46-12:60: StorageLive: StorageLive(_17)
-    12:46-12:55: StorageLive: StorageLive(_18)
-    12:46-12:55: Assign: _18 = _1
-    12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32)
-    12:59-12:60: StorageDead: StorageDead(_18)
-    12:12-12:60: SwitchInt: switchInt(move _17) -&gt; [false: bb14, otherwise: bb13]"><span class="annotation">15⦊</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:59-12:60: StorageDead: StorageDead(_17)
-    12:59-12:60: StorageDead: StorageDead(_12)
-    12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11)
-    12:9-14:10: SwitchInt: switchInt(_11) -&gt; [false: bb22, otherwise: bb21]"><span class="annotation">16⦊</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const true
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">13⦊</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:41-12:42: StorageDead: StorageDead(_15)
-    12:41-12:42: StorageDead: StorageDead(_13)
-    12:12-12:60: SwitchInt: switchInt(move _12) -&gt; [false: bb15, otherwise: bb13]"><span class="annotation">20⦊</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:9-14:10: StorageLive: StorageLive(_10)
-    12:12-12:60: StorageLive: StorageLive(_11)
-    12:12-12:42: StorageLive: StorageLive(_12)
-    12:12-12:25: StorageLive: StorageLive(_13)
-    12:12-12:21: StorageLive: StorageLive(_14)
-    12:12-12:21: Assign: _14 = _1
-    12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32)
-    12:24-12:25: StorageDead: StorageDead(_14)
-    12:12-12:42: SwitchInt: switchInt(move _13) -&gt; [false: bb19, otherwise: bb17]"><span class="annotation">12⦊</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:12-12:42: Assign: _12 = const false
-    12:12-12:42: Goto: goto -&gt; bb20"><span class="annotation">18⦊</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:29-12:42: StorageLive: StorageLive(_15)
-    12:29-12:38: StorageLive: StorageLive(_16)
-    12:29-12:38: Assign: _16 = _1
-    12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32)
-    12:41-12:42: StorageDead: StorageDead(_16)
-    12:12-12:42: SwitchInt: switchInt(move _15) -&gt; [false: bb18, otherwise: bb17]"><span class="annotation">19⦊</span></span><span class="code even" style="--layer: 16" title="bb17: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:12-12:42: Assign: _12 = const true
-    12:12-12:42: Goto: goto -&gt; bb20"><span class="annotation">17⦊</span>countdown &lt; 1 || countdown &gt; 5<span class="annotation">⦉17</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:29-12:42: StorageLive: StorageLive(_15)
-    12:29-12:38: StorageLive: StorageLive(_16)
-    12:29-12:38: Assign: _16 = _1
-    12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32)
-    12:41-12:42: StorageDead: StorageDead(_16)
-    12:12-12:42: SwitchInt: switchInt(move _15) -&gt; [false: bb18, otherwise: bb17]"><span class="annotation">⦉19</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:12-12:42: Assign: _12 = const false
-    12:12-12:42: Goto: goto -&gt; bb20"><span class="annotation">⦉18</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:9-14:10: StorageLive: StorageLive(_10)
-    12:12-12:60: StorageLive: StorageLive(_11)
-    12:12-12:42: StorageLive: StorageLive(_12)
-    12:12-12:25: StorageLive: StorageLive(_13)
-    12:12-12:21: StorageLive: StorageLive(_14)
-    12:12-12:21: Assign: _14 = _1
-    12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32)
-    12:24-12:25: StorageDead: StorageDead(_14)
-    12:12-12:42: SwitchInt: switchInt(move _13) -&gt; [false: bb19, otherwise: bb17]"> || countdown != 9<span class="annotation">⦉12</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:41-12:42: StorageDead: StorageDead(_15)
-    12:41-12:42: StorageDead: StorageDead(_13)
-    12:12-12:60: SwitchInt: switchInt(move _12) -&gt; [false: bb15, otherwise: bb13]"><span class="annotation">⦉20</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const true
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">⦉13</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:59-12:60: StorageDead: StorageDead(_17)
-    12:59-12:60: StorageDead: StorageDead(_12)
-    12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11)
-    12:9-14:10: SwitchInt: switchInt(_11) -&gt; [false: bb22, otherwise: bb21]"><span class="annotation">⦉16</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:46-12:60: StorageLive: StorageLive(_17)
-    12:46-12:55: StorageLive: StorageLive(_18)
-    12:46-12:55: Assign: _18 = _1
-    12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32)
-    12:59-12:60: StorageDead: StorageDead(_18)
-    12:12-12:60: SwitchInt: switchInt(move _17) -&gt; [false: bb14, otherwise: bb13]"><span class="annotation">⦉15</span></span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const false
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">⦉14</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]">            countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]">        </span><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23:
-    14:9-14:10: StorageDead: StorageDead(_11)
-    14:9-14:10: StorageDead: StorageDead(_10)
-    15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32)
-    15:9-15:23: Assert: assert(!move (_19.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 5_i32) -&gt; [success: bb25, unwind: bb1]"><span class="annotation">24⦊</span>}</span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">⦉22</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    13:13-13:26: Assign: _1 = const 0_i32
-    12:61-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">⦉23</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23:
-    14:9-14:10: StorageDead: StorageDead(_11)
-    14:9-14:10: StorageDead: StorageDead(_10)
-    15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32)
-    15:9-15:23: Assert: assert(!move (_19.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 5_i32) -&gt; [success: bb25, unwind: bb1]"></span></span>
-<span class="line"><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23:
-    14:9-14:10: StorageDead: StorageDead(_11)
-    14:9-14:10: StorageDead: StorageDead(_10)
-    15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32)
-    15:9-15:23: Assert: assert(!move (_19.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 5_i32) -&gt; [success: bb25, unwind: bb1]">        countdown -= 5<span class="annotation">⦉24</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">;</span></span>
-<span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">    } else {</span></span>
-<span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">        </span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"><span class="annotation">27⦊</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6:
-    17:9-17:15: Assign: _0 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    17:9-17:15: Goto: goto -&gt; bb27"><span class="annotation">11⦊</span>return;</span></span>
-<span class="line"><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6:
-    17:9-17:15: Assign: _0 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    17:9-17:15: Goto: goto -&gt; bb27">    }<span class="annotation">⦉11</span></span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    9:5-18:6: FalseEdge: falseEdge -&gt; [real: bb8, imaginary: bb7]"><span class="annotation">⦉6</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    10:9-10:23: Assign: _1 = move (_7.0: i32)
-    9:22-11:6: Assign: _4 = const ()
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉9</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6:
-    17:9-17:15: Assign: _0 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    17:9-17:15: Goto: goto -&gt; bb27"><span class="annotation">⦉11</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26">    let mut countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26">    </span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">30⦊</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    22:9-22:23: Assign: _21 = const 10_i32
-    21:13-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">31⦊</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]"><span class="annotation">29⦊</span>if </span><span class="code even" style="--layer: 9" title="bb28: ../instrument-coverage/coverage_of_if_else.rs:21:8: 21:12:
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    20:9-20:22: StorageLive: StorageLive(_21)
-    20:25-20:26: Assign: _21 = const 0_i32
-    20:9-20:22: FakeRead: FakeRead(ForLet, _21)
-    21:5-23:6: StorageLive: StorageLive(_22)
-    21:8-21:12: StorageLive: StorageLive(_23)
-    21:8-21:12: Assign: _23 = const true
-    21:8-21:12: FakeRead: FakeRead(ForMatchedPlace, _23)
-    21:5-23:6: SwitchInt: switchInt(_23) -&gt; [false: bb30, otherwise: bb29]"><span class="annotation">28⦊</span>true<span class="annotation">⦉28</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]">        countdown = 10;</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]">    }<span class="annotation">⦉29</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    22:9-22:23: Assign: _21 = const 10_i32
-    21:13-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">⦉31</span></span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">⦉30</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26">    </span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    25:5-34:6: FalseEdge: falseEdge -&gt; [real: bb35, imaginary: bb34]"><span class="annotation">33⦊</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    31:9-31:23: Assign: _21 = move (_39.0: i32)
-    27:29-32:6: Assign: _24 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">52⦊</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">36⦊</span>if </span><span class="code even" style="--layer: 9" title="bb32: ../instrument-coverage/coverage_of_if_else.rs:25:8: 25:21:
-    23:5-23:6: StorageDead: StorageDead(_23)
-    23:5-23:6: StorageDead: StorageDead(_22)
-    25:5-34:6: StorageLive: StorageLive(_24)
-    25:8-25:21: StorageLive: StorageLive(_25)
-    25:8-25:17: StorageLive: StorageLive(_26)
-    25:8-25:17: Assign: _26 = _21
-    25:8-25:21: Assign: _25 = Gt(move _26, const 7_i32)
-    25:20-25:21: StorageDead: StorageDead(_26)
-    25:8-25:21: FakeRead: FakeRead(ForMatchedPlace, _25)
-    25:5-34:6: SwitchInt: switchInt(_25) -&gt; [false: bb34, otherwise: bb33]"><span class="annotation">32⦊</span>countdown &gt; 7<span class="annotation">⦉32</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53">        </span><span class="code odd" style="--layer: 9" title="bb35: ../instrument-coverage/coverage_of_if_else.rs:26:9: 26:23:
-    26:9-26:23: Assign: _27 = CheckedSub(_21, const 4_i32)
-    26:9-26:23: Assert: assert(!move (_27.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 4_i32) -&gt; [success: bb36, unwind: bb1]"><span class="annotation">35⦊</span>countdown -= 4<span class="annotation">⦉35</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53">;</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53">    } else </span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">37⦊</span>if </span><span class="code even" style="--layer: 10" title="bb34: ../instrument-coverage/coverage_of_if_else.rs:27:15: 27:28:
-    27:15-27:28: StorageLive: StorageLive(_28)
-    27:15-27:24: StorageLive: StorageLive(_29)
-    27:15-27:24: Assign: _29 = _21
-    27:15-27:28: Assign: _28 = Gt(move _29, const 2_i32)
-    27:27-27:28: StorageDead: StorageDead(_29)
-    27:15-27:28: FakeRead: FakeRead(ForMatchedPlace, _28)
-    27:12-34:6: SwitchInt: switchInt(_28) -&gt; [false: bb38, otherwise: bb37]"><span class="annotation">34⦊</span>countdown &gt; 2<span class="annotation">⦉34</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">        </span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: FalseEdge: falseEdge -&gt; [real: bb50, imaginary: bb49]"><span class="annotation">48⦊</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    29:13-29:26: Assign: _21 = const 0_i32
-    28:61-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">50⦊</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">49⦊</span>if </span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:9-30:10: StorageLive: StorageLive(_30)
-    28:12-28:60: StorageLive: StorageLive(_31)
-    28:12-28:42: StorageLive: StorageLive(_32)
-    28:12-28:25: StorageLive: StorageLive(_33)
-    28:12-28:21: StorageLive: StorageLive(_34)
-    28:12-28:21: Assign: _34 = _21
-    28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32)
-    28:24-28:25: StorageDead: StorageDead(_34)
-    28:12-28:42: SwitchInt: switchInt(move _33) -&gt; [false: bb46, otherwise: bb44]"><span class="annotation">39⦊</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:41-28:42: StorageDead: StorageDead(_35)
-    28:41-28:42: StorageDead: StorageDead(_33)
-    28:12-28:60: SwitchInt: switchInt(move _32) -&gt; [false: bb42, otherwise: bb40]"><span class="annotation">47⦊</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const true
-    28:12-28:60: Goto: goto -&gt; bb43"><span class="annotation">40⦊</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:59-28:60: StorageDead: StorageDead(_37)
-    28:59-28:60: StorageDead: StorageDead(_32)
-    28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31)
-    28:9-30:10: SwitchInt: switchInt(_31) -&gt; [false: bb49, otherwise: bb48]"><span class="annotation">43⦊</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:46-28:60: StorageLive: StorageLive(_37)
-    28:46-28:55: StorageLive: StorageLive(_38)
-    28:46-28:55: Assign: _38 = _21
-    28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32)
-    28:59-28:60: StorageDead: StorageDead(_38)
-    28:12-28:60: SwitchInt: switchInt(move _37) -&gt; [false: bb41, otherwise: bb40]"><span class="annotation">42⦊</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const false
-    28:12-28:60: Goto: goto -&gt; bb43"><span class="annotation">41⦊</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:29-28:42: StorageLive: StorageLive(_35)
-    28:29-28:38: StorageLive: StorageLive(_36)
-    28:29-28:38: Assign: _36 = _21
-    28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32)
-    28:41-28:42: StorageDead: StorageDead(_36)
-    28:12-28:42: SwitchInt: switchInt(move _35) -&gt; [false: bb45, otherwise: bb44]"><span class="annotation">46⦊</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:12-28:42: Assign: _32 = const false
-    28:12-28:42: Goto: goto -&gt; bb47"><span class="annotation">45⦊</span></span><span class="code even" style="--layer: 21" title="bb44: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:12-28:42: Assign: _32 = const true
-    28:12-28:42: Goto: goto -&gt; bb47"><span class="annotation">44⦊</span>countdown &lt; 1 || countdown &gt; 5<span class="annotation">⦉44</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:12-28:42: Assign: _32 = const false
-    28:12-28:42: Goto: goto -&gt; bb47"><span class="annotation">⦉45</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:29-28:42: StorageLive: StorageLive(_35)
-    28:29-28:38: StorageLive: StorageLive(_36)
-    28:29-28:38: Assign: _36 = _21
-    28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32)
-    28:41-28:42: StorageDead: StorageDead(_36)
-    28:12-28:42: SwitchInt: switchInt(move _35) -&gt; [false: bb45, otherwise: bb44]"><span class="annotation">⦉46</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const false
-    28:12-28:60: Goto: goto -&gt; bb43"> || countdown != 9<span class="annotation">⦉41</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:46-28:60: StorageLive: StorageLive(_37)
-    28:46-28:55: StorageLive: StorageLive(_38)
-    28:46-28:55: Assign: _38 = _21
-    28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32)
-    28:59-28:60: StorageDead: StorageDead(_38)
-    28:12-28:60: SwitchInt: switchInt(move _37) -&gt; [false: bb41, otherwise: bb40]"><span class="annotation">⦉42</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:59-28:60: StorageDead: StorageDead(_37)
-    28:59-28:60: StorageDead: StorageDead(_32)
-    28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31)
-    28:9-30:10: SwitchInt: switchInt(_31) -&gt; [false: bb49, otherwise: bb48]"><span class="annotation">⦉43</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const true
-    28:12-28:60: Goto: goto -&gt; bb43"><span class="annotation">⦉40</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:41-28:42: StorageDead: StorageDead(_35)
-    28:41-28:42: StorageDead: StorageDead(_33)
-    28:12-28:60: SwitchInt: switchInt(move _32) -&gt; [false: bb42, otherwise: bb40]"><span class="annotation">⦉47</span></span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:9-30:10: StorageLive: StorageLive(_30)
-    28:12-28:60: StorageLive: StorageLive(_31)
-    28:12-28:42: StorageLive: StorageLive(_32)
-    28:12-28:25: StorageLive: StorageLive(_33)
-    28:12-28:21: StorageLive: StorageLive(_34)
-    28:12-28:21: Assign: _34 = _21
-    28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32)
-    28:24-28:25: StorageDead: StorageDead(_34)
-    28:12-28:42: SwitchInt: switchInt(move _33) -&gt; [false: bb46, otherwise: bb44]"><span class="annotation">⦉39</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51">            countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51">        </span><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23:
-    30:9-30:10: StorageDead: StorageDead(_31)
-    30:9-30:10: StorageDead: StorageDead(_30)
-    31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32)
-    31:9-31:23: Assert: assert(!move (_39.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 5_i32) -&gt; [success: bb52, unwind: bb1]"><span class="annotation">51⦊</span>}</span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: FalseEdge: falseEdge -&gt; [real: bb50, imaginary: bb49]"><span class="annotation">⦉48</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    29:13-29:26: Assign: _21 = const 0_i32
-    28:61-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">⦉50</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">⦉49</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">⦉49</span></span><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23:
-    30:9-30:10: StorageDead: StorageDead(_31)
-    30:9-30:10: StorageDead: StorageDead(_30)
-    31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32)
-    31:9-31:23: Assert: assert(!move (_39.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 5_i32) -&gt; [success: bb52, unwind: bb1]"></span></span>
-<span class="line"><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23:
-    30:9-30:10: StorageDead: StorageDead(_31)
-    30:9-30:10: StorageDead: StorageDead(_30)
-    31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32)
-    31:9-31:23: Assert: assert(!move (_39.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 5_i32) -&gt; [success: bb52, unwind: bb1]">        countdown -= 5<span class="annotation">⦉51</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">;</span></span>
-<span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">    } else {</span></span>
-<span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">        </span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"><span class="annotation">38⦊</span>return;</span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    }</span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    25:5-34:6: FalseEdge: falseEdge -&gt; [real: bb35, imaginary: bb34]"><span class="annotation">⦉33</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    31:9-31:23: Assign: _21 = move (_39.0: i32)
-    27:29-32:6: Assign: _24 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉52</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    let mut countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    </span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    38:9-38:23: Assign: _41 = const 10_i32
-    37:13-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"><span class="annotation">56⦊</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: FalseEdge: falseEdge -&gt; [real: bb56, imaginary: bb55]"><span class="annotation">54⦊</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"><span class="annotation">55⦊</span>if </span><span class="code even" style="--layer: 14" title="bb53: ../instrument-coverage/coverage_of_if_else.rs:37:8: 37:12:
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    36:9-36:22: StorageLive: StorageLive(_41)
-    36:25-36:26: Assign: _41 = const 0_i32
-    36:9-36:22: FakeRead: FakeRead(ForLet, _41)
-    37:5-39:6: StorageLive: StorageLive(_42)
-    37:8-37:12: StorageLive: StorageLive(_43)
-    37:8-37:12: Assign: _43 = const true
-    37:8-37:12: FakeRead: FakeRead(ForMatchedPlace, _43)
-    37:5-39:6: SwitchInt: switchInt(_43) -&gt; [false: bb55, otherwise: bb54]"><span class="annotation">53⦊</span>true<span class="annotation">⦉53</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57">        countdown = 10;</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57">    }<span class="annotation">⦉55</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: FalseEdge: falseEdge -&gt; [real: bb56, imaginary: bb55]"><span class="annotation">⦉54</span></span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    38:9-38:23: Assign: _41 = const 10_i32
-    37:13-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"><span class="annotation">⦉56</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    </span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    42:9-42:23: Assign: _41 = move (_46.0: i32)
-    41:22-43:6: Assign: _0 = const ()
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">61⦊</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    41:5-50:6: FalseEdge: falseEdge -&gt; [real: bb60, imaginary: bb59]"><span class="annotation">58⦊</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">77⦊</span>if </span><span class="code even" style="--layer: 14" title="bb57: ../instrument-coverage/coverage_of_if_else.rs:41:8: 41:21:
-    39:5-39:6: StorageDead: StorageDead(_43)
-    39:5-39:6: StorageDead: StorageDead(_42)
-    41:8-41:21: StorageLive: StorageLive(_44)
-    41:8-41:17: StorageLive: StorageLive(_45)
-    41:8-41:17: Assign: _45 = _41
-    41:8-41:21: Assign: _44 = Gt(move _45, const 7_i32)
-    41:20-41:21: StorageDead: StorageDead(_45)
-    41:8-41:21: FakeRead: FakeRead(ForMatchedPlace, _44)
-    41:5-50:6: SwitchInt: switchInt(_44) -&gt; [false: bb59, otherwise: bb58]"><span class="annotation">57⦊</span>countdown &gt; 7<span class="annotation">⦉57</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78">        </span><span class="code odd" style="--layer: 14" title="bb60: ../instrument-coverage/coverage_of_if_else.rs:42:9: 42:23:
-    42:9-42:23: Assign: _46 = CheckedSub(_41, const 4_i32)
-    42:9-42:23: Assert: assert(!move (_46.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 4_i32) -&gt; [success: bb61, unwind: bb1]"><span class="annotation">60⦊</span>countdown -= 4<span class="annotation">⦉60</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78">;</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78">    } else </span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">62⦊</span>if </span><span class="code even" style="--layer: 15" title="bb59: ../instrument-coverage/coverage_of_if_else.rs:43:15: 43:28:
-    43:15-43:28: StorageLive: StorageLive(_47)
-    43:15-43:24: StorageLive: StorageLive(_48)
-    43:15-43:24: Assign: _48 = _41
-    43:15-43:28: Assign: _47 = Gt(move _48, const 2_i32)
-    43:27-43:28: StorageDead: StorageDead(_48)
-    43:15-43:28: FakeRead: FakeRead(ForMatchedPlace, _47)
-    43:12-50:6: SwitchInt: switchInt(_47) -&gt; [false: bb63, otherwise: bb62]"><span class="annotation">59⦊</span>countdown &gt; 2<span class="annotation">⦉59</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">        </span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    45:13-45:26: Assign: _41 = const 0_i32
-    44:61-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">75⦊</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">74⦊</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"><span class="annotation">73⦊</span>if </span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:46-44:60: StorageLive: StorageLive(_56)
-    44:46-44:55: StorageLive: StorageLive(_57)
-    44:46-44:55: Assign: _57 = _41
-    44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32)
-    44:59-44:60: StorageDead: StorageDead(_57)
-    44:12-44:60: SwitchInt: switchInt(move _56) -&gt; [false: bb66, otherwise: bb65]"><span class="annotation">67⦊</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:59-44:60: StorageDead: StorageDead(_56)
-    44:59-44:60: StorageDead: StorageDead(_51)
-    44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50)
-    44:9-46:10: SwitchInt: switchInt(_50) -&gt; [false: bb74, otherwise: bb73]"><span class="annotation">68⦊</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const true
-    44:12-44:60: Goto: goto -&gt; bb68"><span class="annotation">65⦊</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:41-44:42: StorageDead: StorageDead(_54)
-    44:41-44:42: StorageDead: StorageDead(_52)
-    44:12-44:60: SwitchInt: switchInt(move _51) -&gt; [false: bb67, otherwise: bb65]"><span class="annotation">72⦊</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:9-46:10: StorageLive: StorageLive(_49)
-    44:12-44:60: StorageLive: StorageLive(_50)
-    44:12-44:42: StorageLive: StorageLive(_51)
-    44:12-44:25: StorageLive: StorageLive(_52)
-    44:12-44:21: StorageLive: StorageLive(_53)
-    44:12-44:21: Assign: _53 = _41
-    44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32)
-    44:24-44:25: StorageDead: StorageDead(_53)
-    44:12-44:42: SwitchInt: switchInt(move _52) -&gt; [false: bb71, otherwise: bb69]"><span class="annotation">64⦊</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const false
-    44:12-44:60: Goto: goto -&gt; bb68"><span class="annotation">66⦊</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:12-44:42: Assign: _51 = const true
-    44:12-44:42: Goto: goto -&gt; bb72"><span class="annotation">69⦊</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:29-44:42: StorageLive: StorageLive(_54)
-    44:29-44:38: StorageLive: StorageLive(_55)
-    44:29-44:38: Assign: _55 = _41
-    44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32)
-    44:41-44:42: StorageDead: StorageDead(_55)
-    44:12-44:42: SwitchInt: switchInt(move _54) -&gt; [false: bb70, otherwise: bb69]"><span class="annotation">71⦊</span></span><span class="code even" style="--layer: 26" title="bb70: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:12-44:42: Assign: _51 = const false
-    44:12-44:42: Goto: goto -&gt; bb72"><span class="annotation">70⦊</span>countdown &lt; 1 || countdown &gt; 5<span class="annotation">⦉70</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:29-44:42: StorageLive: StorageLive(_54)
-    44:29-44:38: StorageLive: StorageLive(_55)
-    44:29-44:38: Assign: _55 = _41
-    44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32)
-    44:41-44:42: StorageDead: StorageDead(_55)
-    44:12-44:42: SwitchInt: switchInt(move _54) -&gt; [false: bb70, otherwise: bb69]"><span class="annotation">⦉71</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:12-44:42: Assign: _51 = const true
-    44:12-44:42: Goto: goto -&gt; bb72"><span class="annotation">⦉69</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const false
-    44:12-44:60: Goto: goto -&gt; bb68"> || countdown != 9<span class="annotation">⦉66</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:9-46:10: StorageLive: StorageLive(_49)
-    44:12-44:60: StorageLive: StorageLive(_50)
-    44:12-44:42: StorageLive: StorageLive(_51)
-    44:12-44:25: StorageLive: StorageLive(_52)
-    44:12-44:21: StorageLive: StorageLive(_53)
-    44:12-44:21: Assign: _53 = _41
-    44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32)
-    44:24-44:25: StorageDead: StorageDead(_53)
-    44:12-44:42: SwitchInt: switchInt(move _52) -&gt; [false: bb71, otherwise: bb69]"><span class="annotation">⦉64</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:41-44:42: StorageDead: StorageDead(_54)
-    44:41-44:42: StorageDead: StorageDead(_52)
-    44:12-44:60: SwitchInt: switchInt(move _51) -&gt; [false: bb67, otherwise: bb65]"><span class="annotation">⦉72</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const true
-    44:12-44:60: Goto: goto -&gt; bb68"><span class="annotation">⦉65</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:59-44:60: StorageDead: StorageDead(_56)
-    44:59-44:60: StorageDead: StorageDead(_51)
-    44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50)
-    44:9-46:10: SwitchInt: switchInt(_50) -&gt; [false: bb74, otherwise: bb73]"><span class="annotation">⦉68</span></span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:46-44:60: StorageLive: StorageLive(_56)
-    44:46-44:55: StorageLive: StorageLive(_57)
-    44:46-44:55: Assign: _57 = _41
-    44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32)
-    44:59-44:60: StorageDead: StorageDead(_57)
-    44:12-44:60: SwitchInt: switchInt(move _56) -&gt; [false: bb66, otherwise: bb65]"><span class="annotation">⦉67</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]">            countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]">        </span><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23:
-    46:9-46:10: StorageDead: StorageDead(_50)
-    46:9-46:10: StorageDead: StorageDead(_49)
-    47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32)
-    47:9-47:23: Assert: assert(!move (_58.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 5_i32) -&gt; [success: bb77, unwind: bb1]"><span class="annotation">76⦊</span>}</span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    45:13-45:26: Assign: _41 = const 0_i32
-    44:61-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">⦉75</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">⦉74</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23:
-    46:9-46:10: StorageDead: StorageDead(_50)
-    46:9-46:10: StorageDead: StorageDead(_49)
-    47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32)
-    47:9-47:23: Assert: assert(!move (_58.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 5_i32) -&gt; [success: bb77, unwind: bb1]"></span></span>
-<span class="line"><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23:
-    46:9-46:10: StorageDead: StorageDead(_50)
-    46:9-46:10: StorageDead: StorageDead(_49)
-    47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32)
-    47:9-47:23: Assert: assert(!move (_58.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 5_i32) -&gt; [success: bb77, unwind: bb1]">        countdown -= 5<span class="annotation">⦉76</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">;</span></span>
-<span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">    } else {</span></span>
-<span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">        </span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26"><span class="annotation">63⦊</span>return;</span></span>
-<span class="line"><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26">    }</span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    42:9-42:23: Assign: _41 = move (_46.0: i32)
-    41:22-43:6: Assign: _0 = const ()
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉61</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    41:5-50:6: FalseEdge: falseEdge -&gt; [real: bb60, imaginary: bb59]"><span class="annotation">⦉58</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 16" title="bb78: ../instrument-coverage/coverage_of_if_else.rs:51:1: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    51:2-51:2: Goto: goto -&gt; bb26"><span class="annotation">78⦊</span>}<span class="annotation">⦉78</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26"><span class="annotation">⦉63</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"><span class="annotation">⦉38</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"><span class="annotation">⦉27</span></span><span><span class="code even" style="--layer: 1" title="bb26: ../instrument-coverage/coverage_of_if_else.rs:51:2: 51:2:
-    51:2-51:2: Return: return"><span class="annotation">26⦊</span>‸<span class="annotation">⦉26</span></span></span></span></div>
-</body>
-</html>
diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile
deleted file mode 100644
index 0578949..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# needs-profiler-support
-# ignore-msvc
-
-# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038
-LINK_DEAD_CODE=yes
-
--include ../instrument-coverage-mir-cov-html-base/Makefile
-
-# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and
-# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`.
-# See ../instrument-coverage/coverage_tools.mk for more information.
\ No newline at end of file
diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html
deleted file mode 100644
index 1ea9aba..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html
+++ /dev/null
@@ -1,808 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>coverage_of_if_else - Code Regions</title>
-    <style>
-    .line {
-        counter-increment: line;
-    }
-    .line:before {
-        content: counter(line) ": ";
-        font-family: Menlo, Monaco, monospace;
-        font-style: italic;
-        width: 3.8em;
-        display: inline-block;
-        text-align: right;
-        filter: opacity(50%);
-        -webkit-user-select: none;
-    }
-    .code {
-        color: #dddddd;
-        background-color: #222222;
-        font-family: Menlo, Monaco, monospace;
-        line-height: 1.4em;
-        border-bottom: 2px solid #222222;
-        white-space: pre;
-        display: inline-block;
-    }
-    .odd {
-        background-color: #55bbff;
-        color: #223311;
-    }
-    .even {
-        background-color: #ee7756;
-        color: #551133;
-    }
-    .code {
-        --index: calc(var(--layer) - 1);
-        padding-top: calc(var(--index) * 0.15em);
-        filter:
-            hue-rotate(calc(var(--index) * 25deg))
-            saturate(calc(100% - (var(--index) * 2%)))
-            brightness(calc(100% - (var(--index) * 1.5%)));
-    }
-    .annotation {
-        color: #4444ff;
-        font-family: monospace;
-        font-style: italic;
-        display: none;
-        -webkit-user-select: none;
-    }
-    body:active .annotation {
-        /* requires holding mouse down anywhere on the page */
-        display: inline-block;
-    }
-    span:hover .annotation {
-        /* requires hover over a span ONLY on its first line */
-        display: inline-block;
-    }
-    </style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 2"><span class="line"><span class="code" style="--layer: 0">fn main() {</span></span>
-<span class="line"><span class="code" style="--layer: 0">    let mut countdown = 0;</span></span>
-<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: FalseEdge: falseEdge -&gt; [real: bb4, imaginary: bb3]"><span class="annotation">2⦊</span></span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    6:9-6:23: Assign: _1 = const 10_i32
-    5:13-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"><span class="annotation">4⦊</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"><span class="annotation">3⦊</span>if </span><span class="code even" style="--layer: 4" title="bb0: ../instrument-coverage/coverage_of_if_else.rs:5:8: 5:12:
-    4:9-4:22: StorageLive: StorageLive(_1)
-    4:25-4:26: Assign: _1 = const 0_i32
-    4:9-4:22: FakeRead: FakeRead(ForLet, _1)
-    5:5-7:6: StorageLive: StorageLive(_2)
-    5:8-5:12: StorageLive: StorageLive(_3)
-    5:8-5:12: Assign: _3 = const true
-    5:8-5:12: FakeRead: FakeRead(ForMatchedPlace, _3)
-    5:5-7:6: SwitchInt: switchInt(_3) -&gt; [false: bb3, otherwise: bb2]"><span class="annotation">0⦊</span>true<span class="annotation">⦉0</span></span><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5">        countdown = 10;</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb3: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5">    }<span class="annotation">⦉3</span></span><span class="code even" style="--layer: 2" title="bb4: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    6:9-6:23: Assign: _1 = const 10_i32
-    5:13-7:6: Assign: _2 = const ()
-    5:5-7:6: Goto: goto -&gt; bb5"><span class="annotation">⦉4</span></span><span><span class="code even" style="--layer: 1" title="bb2: ../instrument-coverage/coverage_of_if_else.rs:5:5: 7:6:
-    5:5-7:6: FalseEdge: falseEdge -&gt; [real: bb4, imaginary: bb3]"><span class="annotation">⦉2</span></span></span><span class="code" style="--layer: 0"></span></span>
-<span class="line"><span class="code" style="--layer: 0"></span></span>
-<span class="line"><span class="code" style="--layer: 0">    </span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    9:5-18:6: FalseEdge: falseEdge -&gt; [real: bb8, imaginary: bb7]"><span class="annotation">6⦊</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    10:9-10:23: Assign: _1 = move (_7.0: i32)
-    9:22-11:6: Assign: _4 = const ()
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">9⦊</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">25⦊</span>if </span><span class="code even" style="--layer: 4" title="bb5: ../instrument-coverage/coverage_of_if_else.rs:9:8: 9:21:
-    7:5-7:6: StorageDead: StorageDead(_3)
-    7:5-7:6: StorageDead: StorageDead(_2)
-    9:5-18:6: StorageLive: StorageLive(_4)
-    9:8-9:21: StorageLive: StorageLive(_5)
-    9:8-9:17: StorageLive: StorageLive(_6)
-    9:8-9:17: Assign: _6 = _1
-    9:8-9:21: Assign: _5 = Gt(move _6, const 7_i32)
-    9:20-9:21: StorageDead: StorageDead(_6)
-    9:8-9:21: FakeRead: FakeRead(ForMatchedPlace, _5)
-    9:5-18:6: SwitchInt: switchInt(_5) -&gt; [false: bb7, otherwise: bb6]"><span class="annotation">5⦊</span>countdown &gt; 7<span class="annotation">⦉5</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28">        </span><span class="code odd" style="--layer: 4" title="bb8: ../instrument-coverage/coverage_of_if_else.rs:10:9: 10:23:
-    10:9-10:23: Assign: _7 = CheckedSub(_1, const 4_i32)
-    10:9-10:23: Assert: assert(!move (_7.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 4_i32) -&gt; [success: bb9, unwind: bb1]"><span class="annotation">8⦊</span>countdown -= 4<span class="annotation">⦉8</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28">;</span></span>
-<span class="line"><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28">    } else </span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">10⦊</span>if </span><span class="code even" style="--layer: 5" title="bb7: ../instrument-coverage/coverage_of_if_else.rs:11:15: 11:28:
-    11:15-11:28: StorageLive: StorageLive(_8)
-    11:15-11:24: StorageLive: StorageLive(_9)
-    11:15-11:24: Assign: _9 = _1
-    11:15-11:28: Assign: _8 = Gt(move _9, const 2_i32)
-    11:27-11:28: StorageDead: StorageDead(_9)
-    11:15-11:28: FakeRead: FakeRead(ForMatchedPlace, _8)
-    11:12-18:6: SwitchInt: switchInt(_8) -&gt; [false: bb11, otherwise: bb10]"><span class="annotation">7⦊</span>countdown &gt; 2<span class="annotation">⦉7</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">        </span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">22⦊</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    13:13-13:26: Assign: _1 = const 0_i32
-    12:61-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">23⦊</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"><span class="annotation">21⦊</span>if </span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const false
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">14⦊</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:46-12:60: StorageLive: StorageLive(_17)
-    12:46-12:55: StorageLive: StorageLive(_18)
-    12:46-12:55: Assign: _18 = _1
-    12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32)
-    12:59-12:60: StorageDead: StorageDead(_18)
-    12:12-12:60: SwitchInt: switchInt(move _17) -&gt; [false: bb14, otherwise: bb13]"><span class="annotation">15⦊</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:59-12:60: StorageDead: StorageDead(_17)
-    12:59-12:60: StorageDead: StorageDead(_12)
-    12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11)
-    12:9-14:10: SwitchInt: switchInt(_11) -&gt; [false: bb22, otherwise: bb21]"><span class="annotation">16⦊</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const true
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">13⦊</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:41-12:42: StorageDead: StorageDead(_15)
-    12:41-12:42: StorageDead: StorageDead(_13)
-    12:12-12:60: SwitchInt: switchInt(move _12) -&gt; [false: bb15, otherwise: bb13]"><span class="annotation">20⦊</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:9-14:10: StorageLive: StorageLive(_10)
-    12:12-12:60: StorageLive: StorageLive(_11)
-    12:12-12:42: StorageLive: StorageLive(_12)
-    12:12-12:25: StorageLive: StorageLive(_13)
-    12:12-12:21: StorageLive: StorageLive(_14)
-    12:12-12:21: Assign: _14 = _1
-    12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32)
-    12:24-12:25: StorageDead: StorageDead(_14)
-    12:12-12:42: SwitchInt: switchInt(move _13) -&gt; [false: bb19, otherwise: bb17]"><span class="annotation">12⦊</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:12-12:42: Assign: _12 = const false
-    12:12-12:42: Goto: goto -&gt; bb20"><span class="annotation">18⦊</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:29-12:42: StorageLive: StorageLive(_15)
-    12:29-12:38: StorageLive: StorageLive(_16)
-    12:29-12:38: Assign: _16 = _1
-    12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32)
-    12:41-12:42: StorageDead: StorageDead(_16)
-    12:12-12:42: SwitchInt: switchInt(move _15) -&gt; [false: bb18, otherwise: bb17]"><span class="annotation">19⦊</span></span><span class="code even" style="--layer: 16" title="bb17: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:12-12:42: Assign: _12 = const true
-    12:12-12:42: Goto: goto -&gt; bb20"><span class="annotation">17⦊</span>countdown &lt; 1 || countdown &gt; 5<span class="annotation">⦉17</span></span><span class="code even" style="--layer: 15" title="bb19: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:29-12:42: StorageLive: StorageLive(_15)
-    12:29-12:38: StorageLive: StorageLive(_16)
-    12:29-12:38: Assign: _16 = _1
-    12:29-12:42: Assign: _15 = Gt(move _16, const 5_i32)
-    12:41-12:42: StorageDead: StorageDead(_16)
-    12:12-12:42: SwitchInt: switchInt(move _15) -&gt; [false: bb18, otherwise: bb17]"><span class="annotation">⦉19</span></span><span class="code even" style="--layer: 14" title="bb18: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:42:
-    12:12-12:42: Assign: _12 = const false
-    12:12-12:42: Goto: goto -&gt; bb20"><span class="annotation">⦉18</span></span><span class="code even" style="--layer: 13" title="bb12: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:9-14:10: StorageLive: StorageLive(_10)
-    12:12-12:60: StorageLive: StorageLive(_11)
-    12:12-12:42: StorageLive: StorageLive(_12)
-    12:12-12:25: StorageLive: StorageLive(_13)
-    12:12-12:21: StorageLive: StorageLive(_14)
-    12:12-12:21: Assign: _14 = _1
-    12:12-12:25: Assign: _13 = Lt(move _14, const 1_i32)
-    12:24-12:25: StorageDead: StorageDead(_14)
-    12:12-12:42: SwitchInt: switchInt(move _13) -&gt; [false: bb19, otherwise: bb17]"> || countdown != 9<span class="annotation">⦉12</span></span><span class="code even" style="--layer: 12" title="bb20: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:41-12:42: StorageDead: StorageDead(_15)
-    12:41-12:42: StorageDead: StorageDead(_13)
-    12:12-12:60: SwitchInt: switchInt(move _12) -&gt; [false: bb15, otherwise: bb13]"><span class="annotation">⦉20</span></span><span class="code even" style="--layer: 11" title="bb13: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const true
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">⦉13</span></span><span class="code even" style="--layer: 10" title="bb16: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:59-12:60: StorageDead: StorageDead(_17)
-    12:59-12:60: StorageDead: StorageDead(_12)
-    12:12-12:60: FakeRead: FakeRead(ForMatchedPlace, _11)
-    12:9-14:10: SwitchInt: switchInt(_11) -&gt; [false: bb22, otherwise: bb21]"><span class="annotation">⦉16</span></span><span class="code even" style="--layer: 9" title="bb15: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:46-12:60: StorageLive: StorageLive(_17)
-    12:46-12:55: StorageLive: StorageLive(_18)
-    12:46-12:55: Assign: _18 = _1
-    12:46-12:60: Assign: _17 = Ne(move _18, const 9_i32)
-    12:59-12:60: StorageDead: StorageDead(_18)
-    12:12-12:60: SwitchInt: switchInt(move _17) -&gt; [false: bb14, otherwise: bb13]"><span class="annotation">⦉15</span></span><span class="code even" style="--layer: 8" title="bb14: ../instrument-coverage/coverage_of_if_else.rs:12:12: 12:60:
-    12:12-12:60: Assign: _11 = const false
-    12:12-12:60: Goto: goto -&gt; bb16"><span class="annotation">⦉14</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]">            countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]">        </span><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23:
-    14:9-14:10: StorageDead: StorageDead(_11)
-    14:9-14:10: StorageDead: StorageDead(_10)
-    15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32)
-    15:9-15:23: Assert: assert(!move (_19.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 5_i32) -&gt; [success: bb25, unwind: bb1]"><span class="annotation">24⦊</span>}</span><span class="code odd" style="--layer: 5" title="bb22: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">⦉22</span></span><span class="code even" style="--layer: 6" title="bb23: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    13:13-13:26: Assign: _1 = const 0_i32
-    12:61-14:10: Assign: _10 = const ()
-    12:9-14:10: Goto: goto -&gt; bb24"><span class="annotation">⦉23</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code even" style="--layer: 7" title="bb21: ../instrument-coverage/coverage_of_if_else.rs:12:9: 14:10:
-    12:9-14:10: FalseEdge: falseEdge -&gt; [real: bb23, imaginary: bb22]"><span class="annotation">⦉21</span></span><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23:
-    14:9-14:10: StorageDead: StorageDead(_11)
-    14:9-14:10: StorageDead: StorageDead(_10)
-    15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32)
-    15:9-15:23: Assert: assert(!move (_19.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 5_i32) -&gt; [success: bb25, unwind: bb1]"></span></span>
-<span class="line"><span class="code odd" style="--layer: 8" title="bb24: ../instrument-coverage/coverage_of_if_else.rs:14:9: 15:23:
-    14:9-14:10: StorageDead: StorageDead(_11)
-    14:9-14:10: StorageDead: StorageDead(_10)
-    15:9-15:23: Assign: _19 = CheckedSub(_1, const 5_i32)
-    15:9-15:23: Assert: assert(!move (_19.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _1, const 5_i32) -&gt; [success: bb25, unwind: bb1]">        countdown -= 5<span class="annotation">⦉24</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">;</span></span>
-<span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">    } else {</span></span>
-<span class="line"><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]">        </span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"><span class="annotation">27⦊</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6:
-    17:9-17:15: Assign: _0 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    17:9-17:15: Goto: goto -&gt; bb27"><span class="annotation">11⦊</span>return;</span></span>
-<span class="line"><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6:
-    17:9-17:15: Assign: _0 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    17:9-17:15: Goto: goto -&gt; bb27">    }<span class="annotation">⦉11</span></span><span><span class="code odd" style="--layer: 1" title="bb6: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    9:5-18:6: FalseEdge: falseEdge -&gt; [real: bb8, imaginary: bb7]"><span class="annotation">⦉6</span></span></span><span class="code even" style="--layer: 2" title="bb9: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    10:9-10:23: Assign: _1 = move (_7.0: i32)
-    9:22-11:6: Assign: _4 = const ()
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉9</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 3" title="bb25: ../instrument-coverage/coverage_of_if_else.rs:9:5: 18:6:
-    15:9-15:23: Assign: _1 = move (_19.0: i32)
-    11:29-16:6: Assign: _4 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    9:5-18:6: Goto: goto -&gt; bb28"><span class="annotation">⦉25</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 4" title="bb10: ../instrument-coverage/coverage_of_if_else.rs:11:12: 18:6:
-    11:12-18:6: FalseEdge: falseEdge -&gt; [real: bb12, imaginary: bb11]"><span class="annotation">⦉10</span></span><span class="code even" style="--layer: 6" title="bb11: ../instrument-coverage/coverage_of_if_else.rs:17:9: 18:6:
-    17:9-17:15: Assign: _0 = const ()
-    18:5-18:6: StorageDead: StorageDead(_8)
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    17:9-17:15: Goto: goto -&gt; bb27"><span class="annotation">⦉11</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26">    let mut countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26">    </span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">30⦊</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    22:9-22:23: Assign: _21 = const 10_i32
-    21:13-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">31⦊</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]"><span class="annotation">29⦊</span>if </span><span class="code even" style="--layer: 9" title="bb28: ../instrument-coverage/coverage_of_if_else.rs:21:8: 21:12:
-    18:5-18:6: StorageDead: StorageDead(_5)
-    18:5-18:6: StorageDead: StorageDead(_4)
-    20:9-20:22: StorageLive: StorageLive(_21)
-    20:25-20:26: Assign: _21 = const 0_i32
-    20:9-20:22: FakeRead: FakeRead(ForLet, _21)
-    21:5-23:6: StorageLive: StorageLive(_22)
-    21:8-21:12: StorageLive: StorageLive(_23)
-    21:8-21:12: Assign: _23 = const true
-    21:8-21:12: FakeRead: FakeRead(ForMatchedPlace, _23)
-    21:5-23:6: SwitchInt: switchInt(_23) -&gt; [false: bb30, otherwise: bb29]"><span class="annotation">28⦊</span>true<span class="annotation">⦉28</span></span><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]">        countdown = 10;</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb29: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: FalseEdge: falseEdge -&gt; [real: bb31, imaginary: bb30]">    }<span class="annotation">⦉29</span></span><span class="code even" style="--layer: 7" title="bb31: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    22:9-22:23: Assign: _21 = const 10_i32
-    21:13-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">⦉31</span></span><span class="code odd" style="--layer: 6" title="bb30: ../instrument-coverage/coverage_of_if_else.rs:21:5: 23:6:
-    21:5-23:6: Assign: _22 = const ()
-    21:5-23:6: Goto: goto -&gt; bb32"><span class="annotation">⦉30</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26">    </span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    25:5-34:6: FalseEdge: falseEdge -&gt; [real: bb35, imaginary: bb34]"><span class="annotation">33⦊</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    31:9-31:23: Assign: _21 = move (_39.0: i32)
-    27:29-32:6: Assign: _24 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">52⦊</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">36⦊</span>if </span><span class="code even" style="--layer: 9" title="bb32: ../instrument-coverage/coverage_of_if_else.rs:25:8: 25:21:
-    23:5-23:6: StorageDead: StorageDead(_23)
-    23:5-23:6: StorageDead: StorageDead(_22)
-    25:5-34:6: StorageLive: StorageLive(_24)
-    25:8-25:21: StorageLive: StorageLive(_25)
-    25:8-25:17: StorageLive: StorageLive(_26)
-    25:8-25:17: Assign: _26 = _21
-    25:8-25:21: Assign: _25 = Gt(move _26, const 7_i32)
-    25:20-25:21: StorageDead: StorageDead(_26)
-    25:8-25:21: FakeRead: FakeRead(ForMatchedPlace, _25)
-    25:5-34:6: SwitchInt: switchInt(_25) -&gt; [false: bb34, otherwise: bb33]"><span class="annotation">32⦊</span>countdown &gt; 7<span class="annotation">⦉32</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53">        </span><span class="code odd" style="--layer: 9" title="bb35: ../instrument-coverage/coverage_of_if_else.rs:26:9: 26:23:
-    26:9-26:23: Assign: _27 = CheckedSub(_21, const 4_i32)
-    26:9-26:23: Assert: assert(!move (_27.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 4_i32) -&gt; [success: bb36, unwind: bb1]"><span class="annotation">35⦊</span>countdown -= 4<span class="annotation">⦉35</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53">;</span></span>
-<span class="line"><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53">    } else </span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">37⦊</span>if </span><span class="code even" style="--layer: 10" title="bb34: ../instrument-coverage/coverage_of_if_else.rs:27:15: 27:28:
-    27:15-27:28: StorageLive: StorageLive(_28)
-    27:15-27:24: StorageLive: StorageLive(_29)
-    27:15-27:24: Assign: _29 = _21
-    27:15-27:28: Assign: _28 = Gt(move _29, const 2_i32)
-    27:27-27:28: StorageDead: StorageDead(_29)
-    27:15-27:28: FakeRead: FakeRead(ForMatchedPlace, _28)
-    27:12-34:6: SwitchInt: switchInt(_28) -&gt; [false: bb38, otherwise: bb37]"><span class="annotation">34⦊</span>countdown &gt; 2<span class="annotation">⦉34</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">        </span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: FalseEdge: falseEdge -&gt; [real: bb50, imaginary: bb49]"><span class="annotation">48⦊</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    29:13-29:26: Assign: _21 = const 0_i32
-    28:61-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">50⦊</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">49⦊</span>if </span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:9-30:10: StorageLive: StorageLive(_30)
-    28:12-28:60: StorageLive: StorageLive(_31)
-    28:12-28:42: StorageLive: StorageLive(_32)
-    28:12-28:25: StorageLive: StorageLive(_33)
-    28:12-28:21: StorageLive: StorageLive(_34)
-    28:12-28:21: Assign: _34 = _21
-    28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32)
-    28:24-28:25: StorageDead: StorageDead(_34)
-    28:12-28:42: SwitchInt: switchInt(move _33) -&gt; [false: bb46, otherwise: bb44]"><span class="annotation">39⦊</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:41-28:42: StorageDead: StorageDead(_35)
-    28:41-28:42: StorageDead: StorageDead(_33)
-    28:12-28:60: SwitchInt: switchInt(move _32) -&gt; [false: bb42, otherwise: bb40]"><span class="annotation">47⦊</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const true
-    28:12-28:60: Goto: goto -&gt; bb43"><span class="annotation">40⦊</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:59-28:60: StorageDead: StorageDead(_37)
-    28:59-28:60: StorageDead: StorageDead(_32)
-    28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31)
-    28:9-30:10: SwitchInt: switchInt(_31) -&gt; [false: bb49, otherwise: bb48]"><span class="annotation">43⦊</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:46-28:60: StorageLive: StorageLive(_37)
-    28:46-28:55: StorageLive: StorageLive(_38)
-    28:46-28:55: Assign: _38 = _21
-    28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32)
-    28:59-28:60: StorageDead: StorageDead(_38)
-    28:12-28:60: SwitchInt: switchInt(move _37) -&gt; [false: bb41, otherwise: bb40]"><span class="annotation">42⦊</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const false
-    28:12-28:60: Goto: goto -&gt; bb43"><span class="annotation">41⦊</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:29-28:42: StorageLive: StorageLive(_35)
-    28:29-28:38: StorageLive: StorageLive(_36)
-    28:29-28:38: Assign: _36 = _21
-    28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32)
-    28:41-28:42: StorageDead: StorageDead(_36)
-    28:12-28:42: SwitchInt: switchInt(move _35) -&gt; [false: bb45, otherwise: bb44]"><span class="annotation">46⦊</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:12-28:42: Assign: _32 = const false
-    28:12-28:42: Goto: goto -&gt; bb47"><span class="annotation">45⦊</span></span><span class="code even" style="--layer: 21" title="bb44: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:12-28:42: Assign: _32 = const true
-    28:12-28:42: Goto: goto -&gt; bb47"><span class="annotation">44⦊</span>countdown &lt; 1 || countdown &gt; 5<span class="annotation">⦉44</span></span><span class="code even" style="--layer: 20" title="bb45: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:12-28:42: Assign: _32 = const false
-    28:12-28:42: Goto: goto -&gt; bb47"><span class="annotation">⦉45</span></span><span class="code even" style="--layer: 19" title="bb46: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:42:
-    28:29-28:42: StorageLive: StorageLive(_35)
-    28:29-28:38: StorageLive: StorageLive(_36)
-    28:29-28:38: Assign: _36 = _21
-    28:29-28:42: Assign: _35 = Gt(move _36, const 5_i32)
-    28:41-28:42: StorageDead: StorageDead(_36)
-    28:12-28:42: SwitchInt: switchInt(move _35) -&gt; [false: bb45, otherwise: bb44]"><span class="annotation">⦉46</span></span><span class="code even" style="--layer: 18" title="bb41: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const false
-    28:12-28:60: Goto: goto -&gt; bb43"> || countdown != 9<span class="annotation">⦉41</span></span><span class="code even" style="--layer: 17" title="bb42: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:46-28:60: StorageLive: StorageLive(_37)
-    28:46-28:55: StorageLive: StorageLive(_38)
-    28:46-28:55: Assign: _38 = _21
-    28:46-28:60: Assign: _37 = Ne(move _38, const 9_i32)
-    28:59-28:60: StorageDead: StorageDead(_38)
-    28:12-28:60: SwitchInt: switchInt(move _37) -&gt; [false: bb41, otherwise: bb40]"><span class="annotation">⦉42</span></span><span class="code even" style="--layer: 16" title="bb43: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:59-28:60: StorageDead: StorageDead(_37)
-    28:59-28:60: StorageDead: StorageDead(_32)
-    28:12-28:60: FakeRead: FakeRead(ForMatchedPlace, _31)
-    28:9-30:10: SwitchInt: switchInt(_31) -&gt; [false: bb49, otherwise: bb48]"><span class="annotation">⦉43</span></span><span class="code even" style="--layer: 15" title="bb40: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:12-28:60: Assign: _31 = const true
-    28:12-28:60: Goto: goto -&gt; bb43"><span class="annotation">⦉40</span></span><span class="code even" style="--layer: 14" title="bb47: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:41-28:42: StorageDead: StorageDead(_35)
-    28:41-28:42: StorageDead: StorageDead(_33)
-    28:12-28:60: SwitchInt: switchInt(move _32) -&gt; [false: bb42, otherwise: bb40]"><span class="annotation">⦉47</span></span><span class="code even" style="--layer: 13" title="bb39: ../instrument-coverage/coverage_of_if_else.rs:28:12: 28:60:
-    28:9-30:10: StorageLive: StorageLive(_30)
-    28:12-28:60: StorageLive: StorageLive(_31)
-    28:12-28:42: StorageLive: StorageLive(_32)
-    28:12-28:25: StorageLive: StorageLive(_33)
-    28:12-28:21: StorageLive: StorageLive(_34)
-    28:12-28:21: Assign: _34 = _21
-    28:12-28:25: Assign: _33 = Lt(move _34, const 1_i32)
-    28:24-28:25: StorageDead: StorageDead(_34)
-    28:12-28:42: SwitchInt: switchInt(move _33) -&gt; [false: bb46, otherwise: bb44]"><span class="annotation">⦉39</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51">            countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51">        </span><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23:
-    30:9-30:10: StorageDead: StorageDead(_31)
-    30:9-30:10: StorageDead: StorageDead(_30)
-    31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32)
-    31:9-31:23: Assert: assert(!move (_39.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 5_i32) -&gt; [success: bb52, unwind: bb1]"><span class="annotation">51⦊</span>}</span><span class="code odd" style="--layer: 10" title="bb48: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: FalseEdge: falseEdge -&gt; [real: bb50, imaginary: bb49]"><span class="annotation">⦉48</span></span><span class="code even" style="--layer: 11" title="bb50: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    29:13-29:26: Assign: _21 = const 0_i32
-    28:61-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">⦉50</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">⦉49</span></span><span class="code even" style="--layer: 12" title="bb49: ../instrument-coverage/coverage_of_if_else.rs:28:9: 30:10:
-    28:9-30:10: Assign: _30 = const ()
-    28:9-30:10: Goto: goto -&gt; bb51"><span class="annotation">⦉49</span></span><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23:
-    30:9-30:10: StorageDead: StorageDead(_31)
-    30:9-30:10: StorageDead: StorageDead(_30)
-    31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32)
-    31:9-31:23: Assert: assert(!move (_39.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 5_i32) -&gt; [success: bb52, unwind: bb1]"></span></span>
-<span class="line"><span class="code odd" style="--layer: 13" title="bb51: ../instrument-coverage/coverage_of_if_else.rs:30:9: 31:23:
-    30:9-30:10: StorageDead: StorageDead(_31)
-    30:9-30:10: StorageDead: StorageDead(_30)
-    31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32)
-    31:9-31:23: Assert: assert(!move (_39.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _21, const 5_i32) -&gt; [success: bb52, unwind: bb1]">        countdown -= 5<span class="annotation">⦉51</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">;</span></span>
-<span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">    } else {</span></span>
-<span class="line"><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]">        </span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"><span class="annotation">38⦊</span>return;</span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    }</span><span class="code even" style="--layer: 6" title="bb33: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    25:5-34:6: FalseEdge: falseEdge -&gt; [real: bb35, imaginary: bb34]"><span class="annotation">⦉33</span></span><span class="code even" style="--layer: 7" title="bb52: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    31:9-31:23: Assign: _21 = move (_39.0: i32)
-    27:29-32:6: Assign: _24 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉52</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 8" title="bb36: ../instrument-coverage/coverage_of_if_else.rs:25:5: 34:6:
-    26:9-26:23: Assign: _21 = move (_27.0: i32)
-    25:22-27:6: Assign: _24 = const ()
-    25:5-34:6: Goto: goto -&gt; bb53"><span class="annotation">⦉36</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 9" title="bb37: ../instrument-coverage/coverage_of_if_else.rs:27:12: 34:6:
-    27:12-34:6: FalseEdge: falseEdge -&gt; [real: bb39, imaginary: bb38]"><span class="annotation">⦉37</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    let mut countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    </span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    38:9-38:23: Assign: _41 = const 10_i32
-    37:13-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"><span class="annotation">56⦊</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: FalseEdge: falseEdge -&gt; [real: bb56, imaginary: bb55]"><span class="annotation">54⦊</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"><span class="annotation">55⦊</span>if </span><span class="code even" style="--layer: 14" title="bb53: ../instrument-coverage/coverage_of_if_else.rs:37:8: 37:12:
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    36:9-36:22: StorageLive: StorageLive(_41)
-    36:25-36:26: Assign: _41 = const 0_i32
-    36:9-36:22: FakeRead: FakeRead(ForLet, _41)
-    37:5-39:6: StorageLive: StorageLive(_42)
-    37:8-37:12: StorageLive: StorageLive(_43)
-    37:8-37:12: Assign: _43 = const true
-    37:8-37:12: FakeRead: FakeRead(ForMatchedPlace, _43)
-    37:5-39:6: SwitchInt: switchInt(_43) -&gt; [false: bb55, otherwise: bb54]"><span class="annotation">53⦊</span>true<span class="annotation">⦉53</span></span><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57">        countdown = 10;</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb55: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57">    }<span class="annotation">⦉55</span></span><span class="code even" style="--layer: 12" title="bb54: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    37:5-39:6: FalseEdge: falseEdge -&gt; [real: bb56, imaginary: bb55]"><span class="annotation">⦉54</span></span><span class="code even" style="--layer: 11" title="bb56: ../instrument-coverage/coverage_of_if_else.rs:37:5: 39:6:
-    38:9-38:23: Assign: _41 = const 10_i32
-    37:13-39:6: Assign: _42 = const ()
-    37:5-39:6: Goto: goto -&gt; bb57"><span class="annotation">⦉56</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"></span></span>
-<span class="line"><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27">    </span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    42:9-42:23: Assign: _41 = move (_46.0: i32)
-    41:22-43:6: Assign: _0 = const ()
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">61⦊</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    41:5-50:6: FalseEdge: falseEdge -&gt; [real: bb60, imaginary: bb59]"><span class="annotation">58⦊</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">77⦊</span>if </span><span class="code even" style="--layer: 14" title="bb57: ../instrument-coverage/coverage_of_if_else.rs:41:8: 41:21:
-    39:5-39:6: StorageDead: StorageDead(_43)
-    39:5-39:6: StorageDead: StorageDead(_42)
-    41:8-41:21: StorageLive: StorageLive(_44)
-    41:8-41:17: StorageLive: StorageLive(_45)
-    41:8-41:17: Assign: _45 = _41
-    41:8-41:21: Assign: _44 = Gt(move _45, const 7_i32)
-    41:20-41:21: StorageDead: StorageDead(_45)
-    41:8-41:21: FakeRead: FakeRead(ForMatchedPlace, _44)
-    41:5-50:6: SwitchInt: switchInt(_44) -&gt; [false: bb59, otherwise: bb58]"><span class="annotation">57⦊</span>countdown &gt; 7<span class="annotation">⦉57</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78">        </span><span class="code odd" style="--layer: 14" title="bb60: ../instrument-coverage/coverage_of_if_else.rs:42:9: 42:23:
-    42:9-42:23: Assign: _46 = CheckedSub(_41, const 4_i32)
-    42:9-42:23: Assert: assert(!move (_46.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 4_i32) -&gt; [success: bb61, unwind: bb1]"><span class="annotation">60⦊</span>countdown -= 4<span class="annotation">⦉60</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78">;</span></span>
-<span class="line"><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78">    } else </span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">62⦊</span>if </span><span class="code even" style="--layer: 15" title="bb59: ../instrument-coverage/coverage_of_if_else.rs:43:15: 43:28:
-    43:15-43:28: StorageLive: StorageLive(_47)
-    43:15-43:24: StorageLive: StorageLive(_48)
-    43:15-43:24: Assign: _48 = _41
-    43:15-43:28: Assign: _47 = Gt(move _48, const 2_i32)
-    43:27-43:28: StorageDead: StorageDead(_48)
-    43:15-43:28: FakeRead: FakeRead(ForMatchedPlace, _47)
-    43:12-50:6: SwitchInt: switchInt(_47) -&gt; [false: bb63, otherwise: bb62]"><span class="annotation">59⦊</span>countdown &gt; 2<span class="annotation">⦉59</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">        </span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    45:13-45:26: Assign: _41 = const 0_i32
-    44:61-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">75⦊</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">74⦊</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"><span class="annotation">73⦊</span>if </span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:46-44:60: StorageLive: StorageLive(_56)
-    44:46-44:55: StorageLive: StorageLive(_57)
-    44:46-44:55: Assign: _57 = _41
-    44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32)
-    44:59-44:60: StorageDead: StorageDead(_57)
-    44:12-44:60: SwitchInt: switchInt(move _56) -&gt; [false: bb66, otherwise: bb65]"><span class="annotation">67⦊</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:59-44:60: StorageDead: StorageDead(_56)
-    44:59-44:60: StorageDead: StorageDead(_51)
-    44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50)
-    44:9-46:10: SwitchInt: switchInt(_50) -&gt; [false: bb74, otherwise: bb73]"><span class="annotation">68⦊</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const true
-    44:12-44:60: Goto: goto -&gt; bb68"><span class="annotation">65⦊</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:41-44:42: StorageDead: StorageDead(_54)
-    44:41-44:42: StorageDead: StorageDead(_52)
-    44:12-44:60: SwitchInt: switchInt(move _51) -&gt; [false: bb67, otherwise: bb65]"><span class="annotation">72⦊</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:9-46:10: StorageLive: StorageLive(_49)
-    44:12-44:60: StorageLive: StorageLive(_50)
-    44:12-44:42: StorageLive: StorageLive(_51)
-    44:12-44:25: StorageLive: StorageLive(_52)
-    44:12-44:21: StorageLive: StorageLive(_53)
-    44:12-44:21: Assign: _53 = _41
-    44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32)
-    44:24-44:25: StorageDead: StorageDead(_53)
-    44:12-44:42: SwitchInt: switchInt(move _52) -&gt; [false: bb71, otherwise: bb69]"><span class="annotation">64⦊</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const false
-    44:12-44:60: Goto: goto -&gt; bb68"><span class="annotation">66⦊</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:12-44:42: Assign: _51 = const true
-    44:12-44:42: Goto: goto -&gt; bb72"><span class="annotation">69⦊</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:29-44:42: StorageLive: StorageLive(_54)
-    44:29-44:38: StorageLive: StorageLive(_55)
-    44:29-44:38: Assign: _55 = _41
-    44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32)
-    44:41-44:42: StorageDead: StorageDead(_55)
-    44:12-44:42: SwitchInt: switchInt(move _54) -&gt; [false: bb70, otherwise: bb69]"><span class="annotation">71⦊</span></span><span class="code even" style="--layer: 26" title="bb70: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:12-44:42: Assign: _51 = const false
-    44:12-44:42: Goto: goto -&gt; bb72"><span class="annotation">70⦊</span>countdown &lt; 1 || countdown &gt; 5<span class="annotation">⦉70</span></span><span class="code even" style="--layer: 25" title="bb71: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:29-44:42: StorageLive: StorageLive(_54)
-    44:29-44:38: StorageLive: StorageLive(_55)
-    44:29-44:38: Assign: _55 = _41
-    44:29-44:42: Assign: _54 = Gt(move _55, const 5_i32)
-    44:41-44:42: StorageDead: StorageDead(_55)
-    44:12-44:42: SwitchInt: switchInt(move _54) -&gt; [false: bb70, otherwise: bb69]"><span class="annotation">⦉71</span></span><span class="code even" style="--layer: 24" title="bb69: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:42:
-    44:12-44:42: Assign: _51 = const true
-    44:12-44:42: Goto: goto -&gt; bb72"><span class="annotation">⦉69</span></span><span class="code even" style="--layer: 23" title="bb66: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const false
-    44:12-44:60: Goto: goto -&gt; bb68"> || countdown != 9<span class="annotation">⦉66</span></span><span class="code even" style="--layer: 22" title="bb64: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:9-46:10: StorageLive: StorageLive(_49)
-    44:12-44:60: StorageLive: StorageLive(_50)
-    44:12-44:42: StorageLive: StorageLive(_51)
-    44:12-44:25: StorageLive: StorageLive(_52)
-    44:12-44:21: StorageLive: StorageLive(_53)
-    44:12-44:21: Assign: _53 = _41
-    44:12-44:25: Assign: _52 = Lt(move _53, const 1_i32)
-    44:24-44:25: StorageDead: StorageDead(_53)
-    44:12-44:42: SwitchInt: switchInt(move _52) -&gt; [false: bb71, otherwise: bb69]"><span class="annotation">⦉64</span></span><span class="code even" style="--layer: 21" title="bb72: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:41-44:42: StorageDead: StorageDead(_54)
-    44:41-44:42: StorageDead: StorageDead(_52)
-    44:12-44:60: SwitchInt: switchInt(move _51) -&gt; [false: bb67, otherwise: bb65]"><span class="annotation">⦉72</span></span><span class="code even" style="--layer: 20" title="bb65: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:12-44:60: Assign: _50 = const true
-    44:12-44:60: Goto: goto -&gt; bb68"><span class="annotation">⦉65</span></span><span class="code even" style="--layer: 19" title="bb68: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:59-44:60: StorageDead: StorageDead(_56)
-    44:59-44:60: StorageDead: StorageDead(_51)
-    44:12-44:60: FakeRead: FakeRead(ForMatchedPlace, _50)
-    44:9-46:10: SwitchInt: switchInt(_50) -&gt; [false: bb74, otherwise: bb73]"><span class="annotation">⦉68</span></span><span class="code even" style="--layer: 18" title="bb67: ../instrument-coverage/coverage_of_if_else.rs:44:12: 44:60:
-    44:46-44:60: StorageLive: StorageLive(_56)
-    44:46-44:55: StorageLive: StorageLive(_57)
-    44:46-44:55: Assign: _57 = _41
-    44:46-44:60: Assign: _56 = Ne(move _57, const 9_i32)
-    44:59-44:60: StorageDead: StorageDead(_57)
-    44:12-44:60: SwitchInt: switchInt(move _56) -&gt; [false: bb66, otherwise: bb65]"><span class="annotation">⦉67</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"> {</span></span>
-<span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]">            countdown = 0;</span></span>
-<span class="line"><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]">        </span><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23:
-    46:9-46:10: StorageDead: StorageDead(_50)
-    46:9-46:10: StorageDead: StorageDead(_49)
-    47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32)
-    47:9-47:23: Assert: assert(!move (_58.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 5_i32) -&gt; [success: bb77, unwind: bb1]"><span class="annotation">76⦊</span>}</span><span class="code odd" style="--layer: 15" title="bb75: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    45:13-45:26: Assign: _41 = const 0_i32
-    44:61-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">⦉75</span></span><span class="code even" style="--layer: 16" title="bb74: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: Assign: _49 = const ()
-    44:9-46:10: Goto: goto -&gt; bb76"><span class="annotation">⦉74</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code even" style="--layer: 17" title="bb73: ../instrument-coverage/coverage_of_if_else.rs:44:9: 46:10:
-    44:9-46:10: FalseEdge: falseEdge -&gt; [real: bb75, imaginary: bb74]"><span class="annotation">⦉73</span></span><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23:
-    46:9-46:10: StorageDead: StorageDead(_50)
-    46:9-46:10: StorageDead: StorageDead(_49)
-    47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32)
-    47:9-47:23: Assert: assert(!move (_58.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 5_i32) -&gt; [success: bb77, unwind: bb1]"></span></span>
-<span class="line"><span class="code odd" style="--layer: 18" title="bb76: ../instrument-coverage/coverage_of_if_else.rs:46:9: 47:23:
-    46:9-46:10: StorageDead: StorageDead(_50)
-    46:9-46:10: StorageDead: StorageDead(_49)
-    47:9-47:23: Assign: _58 = CheckedSub(_41, const 5_i32)
-    47:9-47:23: Assert: assert(!move (_58.1: bool), &quot;attempt to compute `{} - {}` which would overflow&quot;, _41, const 5_i32) -&gt; [success: bb77, unwind: bb1]">        countdown -= 5<span class="annotation">⦉76</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">;</span></span>
-<span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">    } else {</span></span>
-<span class="line"><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]">        </span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26"><span class="annotation">63⦊</span>return;</span></span>
-<span class="line"><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26">    }</span><span class="code odd" style="--layer: 11" title="bb61: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    42:9-42:23: Assign: _41 = move (_46.0: i32)
-    41:22-43:6: Assign: _0 = const ()
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉61</span></span><span class="code even" style="--layer: 12" title="bb58: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    41:5-50:6: FalseEdge: falseEdge -&gt; [real: bb60, imaginary: bb59]"><span class="annotation">⦉58</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 13" title="bb77: ../instrument-coverage/coverage_of_if_else.rs:41:5: 50:6:
-    47:9-47:23: Assign: _41 = move (_58.0: i32)
-    43:29-48:6: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    41:5-50:6: Goto: goto -&gt; bb78"><span class="annotation">⦉77</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 14" title="bb62: ../instrument-coverage/coverage_of_if_else.rs:43:12: 50:6:
-    43:12-50:6: FalseEdge: falseEdge -&gt; [real: bb64, imaginary: bb63]"><span class="annotation">⦉62</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26"></span></span>
-<span class="line"><span class="code even" style="--layer: 16" title="bb78: ../instrument-coverage/coverage_of_if_else.rs:51:1: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    51:2-51:2: Goto: goto -&gt; bb26"><span class="annotation">78⦊</span>}<span class="annotation">⦉78</span></span><span class="code even" style="--layer: 15" title="bb63: ../instrument-coverage/coverage_of_if_else.rs:49:9: 51:2:
-    49:9-49:15: Assign: _0 = const ()
-    50:5-50:6: StorageDead: StorageDead(_47)
-    51:1-51:2: StorageDead: StorageDead(_41)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    51:1-51:2: StorageDead: StorageDead(_1)
-    51:1-51:2: StorageDead: StorageDead(_44)
-    49:9-49:15: Goto: goto -&gt; bb26"><span class="annotation">⦉63</span></span><span class="code even" style="--layer: 10" title="bb38: ../instrument-coverage/coverage_of_if_else.rs:33:9: 51:2:
-    33:9-33:15: Assign: _0 = const ()
-    34:5-34:6: StorageDead: StorageDead(_28)
-    34:5-34:6: StorageDead: StorageDead(_25)
-    34:5-34:6: StorageDead: StorageDead(_24)
-    51:1-51:2: StorageDead: StorageDead(_21)
-    33:9-33:15: Goto: goto -&gt; bb27"><span class="annotation">⦉38</span></span><span class="code even" style="--layer: 5" title="bb27: ../instrument-coverage/coverage_of_if_else.rs:17:9: 51:2:
-    51:1-51:2: StorageDead: StorageDead(_1)
-    17:9-17:15: Goto: goto -&gt; bb26"><span class="annotation">⦉27</span></span><span><span class="code even" style="--layer: 1" title="bb26: ../instrument-coverage/coverage_of_if_else.rs:51:2: 51:2:
-    51:2-51:2: Return: return"><span class="annotation">26⦊</span>‸<span class="annotation">⦉26</span></span></span></span></div>
-</body>
-</html>
diff --git a/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir
deleted file mode 100644
index d57f66a..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir
+++ /dev/null
@@ -1,3 +0,0 @@
-# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-*
-
-# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests.
\ No newline at end of file
diff --git a/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs b/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs
deleted file mode 100644
index 91741cf..0000000
--- a/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-#![allow(unused_assignments)]
-
-fn main() {
-    let mut countdown = 0;
-    if true {
-        countdown = 10;
-    }
-
-    if countdown > 7 {
-        countdown -= 4;
-    } else if countdown > 2 {
-        if countdown < 1 || countdown > 5 || countdown != 9 {
-            countdown = 0;
-        }
-        countdown -= 5;
-    } else {
-        return;
-    }
-
-    let mut countdown = 0;
-    if true {
-        countdown = 10;
-    }
-
-    if countdown > 7 {
-        countdown -= 4;
-    } else if countdown > 2 {
-        if countdown < 1 || countdown > 5 || countdown != 9 {
-            countdown = 0;
-        }
-        countdown -= 5;
-    } else {
-        return;
-    }
-
-    let mut countdown = 0;
-    if true {
-        countdown = 10;
-    }
-
-    if countdown > 7 {
-        countdown -= 4;
-    } else if countdown > 2 {
-        if countdown < 1 || countdown > 5 || countdown != 9 {
-            countdown = 0;
-        }
-        countdown -= 5;
-    } else {
-        return;
-    }
-}
diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index af84faa..2636423 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -60,6 +60,7 @@
         lint_caps: Default::default(),
         register_lints: None,
         override_queries: None,
+        make_codegen_backend: None,
         registry: rustc_driver::diagnostics_registry(),
     };
 
diff --git a/src/test/rustdoc-js/doc-alias-whitespace.js b/src/test/rustdoc-js/doc-alias-whitespace.js
new file mode 100644
index 0000000..c9fc0c4
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-whitespace.js
@@ -0,0 +1,19 @@
+// exact-check
+
+const QUERY = [
+    'Demon Lord',
+];
+
+const EXPECTED = [
+    {
+        'others': [
+            {
+                'path': 'doc_alias_whitespace',
+                'name': 'Struct',
+                'alias': 'Demon Lord',
+                'href': '../doc_alias_whitespace/struct.Struct.html',
+                'is_alias': true
+            },
+        ],
+    },
+];
diff --git a/src/test/rustdoc-js/doc-alias-whitespace.rs b/src/test/rustdoc-js/doc-alias-whitespace.rs
new file mode 100644
index 0000000..bea3e38
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-whitespace.rs
@@ -0,0 +1,4 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "Demon Lord")]
+pub struct Struct;
diff --git a/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs b/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs
new file mode 100644
index 0000000..31a8310
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs
@@ -0,0 +1,4 @@
+#![crate_name = "intra_doc_broken"]
+
+/// [not_found]
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs
index b02cc1a..0ca2349 100644
--- a/src/test/rustdoc-ui/check-doc-alias-attr.rs
+++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs
@@ -7,4 +7,11 @@
 #[doc(alias)] //~ ERROR
 #[doc(alias = 0)] //~ ERROR
 #[doc(alias("bar"))] //~ ERROR
+#[doc(alias = "\"")] //~ ERROR
+#[doc(alias = "\n")] //~ ERROR
+#[doc(alias = "
+")] //~^ ERROR
+#[doc(alias = "\t")] //~ ERROR
+#[doc(alias = " hello")] //~ ERROR
+#[doc(alias = "hello ")] //~ ERROR
 pub struct Foo;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
index 268230a..2c417a3 100644
--- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr
+++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
@@ -16,5 +16,43 @@
 LL | #[doc(alias("bar"))]
    |       ^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: '\"' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:10:7
+   |
+LL | #[doc(alias = "\"")]
+   |       ^^^^^^^^^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:11:7
+   |
+LL | #[doc(alias = "\n")]
+   |       ^^^^^^^^^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:12:7
+   |
+LL |   #[doc(alias = "
+   |  _______^
+LL | | ")]
+   | |_^
+
+error: '\t' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:14:7
+   |
+LL | #[doc(alias = "\t")]
+   |       ^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+  --> $DIR/check-doc-alias-attr.rs:15:7
+   |
+LL | #[doc(alias = " hello")]
+   |       ^^^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+  --> $DIR/check-doc-alias-attr.rs:16:7
+   |
+LL | #[doc(alias = "hello ")]
+   |       ^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
 
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.rs b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs
new file mode 100644
index 0000000..c077be3
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs
@@ -0,0 +1,41 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! Make sure to have some docs on your crate root
+
+#[allow(missing_docs)]
+pub mod mod_foo {
+    pub struct Bar;
+}
+
+/// This is a struct with a `#[allow(missing_docs)]`
+pub struct AllowTheMissingDocs {
+    #[allow(missing_docs)]
+    pub empty_str: String,
+
+    /// This has
+    #[allow(missing_docs)]
+    /// but also has documentation comments
+    pub hello: usize,
+
+    /// The doc id just to create a boilerplate comment
+    pub doc_id: Vec<u8>,
+}
+
+/// A function that has a documentation
+pub fn this_is_func() {}
+
+#[allow(missing_docs)]
+pub struct DemoStruct {
+    something: usize,
+}
+
+#[allow(missing_docs)]
+pub mod bar {
+    #[warn(missing_docs)]
+    pub struct Bar { //~ WARN
+        pub f: u32, //~ WARN
+    }
+
+    pub struct NeedsNoDocs;
+}
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr
new file mode 100644
index 0000000..3d5b512
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr
@@ -0,0 +1,20 @@
+warning: missing documentation for a struct
+  --> $DIR/allow_missing_docs.rs:36:5
+   |
+LL |     pub struct Bar {
+   |     ^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/allow_missing_docs.rs:35:12
+   |
+LL |     #[warn(missing_docs)]
+   |            ^^^^^^^^^^^^
+
+warning: missing documentation for a struct field
+  --> $DIR/allow_missing_docs.rs:37:9
+   |
+LL |         pub f: u32,
+   |         ^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout
new file mode 100644
index 0000000..17e8ee9
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File                                | Documented | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...i/coverage/allow_missing_docs.rs |          5 |      71.4% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total                               |          5 |      71.4% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
index 33260fa..9ec9dd4 100644
--- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
+++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr
@@ -2,7 +2,7 @@
   --> $DIR/deny-intra-link-resolution-failure.rs:3:6
    |
 LL | /// [v2]
-   |      ^^ the module `deny_intra_link_resolution_failure` contains no item named `v2`
+   |      ^^ no item named `v2` in scope
    |
 note: the lint level is defined here
   --> $DIR/deny-intra-link-resolution-failure.rs:1:9
diff --git a/src/test/rustdoc-ui/doc-alias-crate-level.rs b/src/test/rustdoc-ui/doc-alias-crate-level.rs
new file mode 100644
index 0000000..309d0bc
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-crate-level.rs
@@ -0,0 +1,6 @@
+#![feature(doc_alias)]
+
+#![doc(alias = "crate-level-not-working")] //~ ERROR
+
+#[doc(alias = "shouldn't work!")] //~ ERROR
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/doc-alias-crate-level.stderr b/src/test/rustdoc-ui/doc-alias-crate-level.stderr
new file mode 100644
index 0000000..fc14266
--- /dev/null
+++ b/src/test/rustdoc-ui/doc-alias-crate-level.stderr
@@ -0,0 +1,14 @@
+error: '\'' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/doc-alias-crate-level.rs:5:7
+   |
+LL | #[doc(alias = "shouldn't work!")]
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `#![doc(alias = "...")]` isn't allowed as a crate level attribute
+  --> $DIR/doc-alias-crate-level.rs:3:8
+   |
+LL | #![doc(alias = "crate-level-not-working")]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-doc-broken-reexport.rs b/src/test/rustdoc-ui/intra-doc-broken-reexport.rs
new file mode 100644
index 0000000..ef26135
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc-broken-reexport.rs
@@ -0,0 +1,8 @@
+// aux-build:intra-doc-broken.rs
+// check-pass
+
+#![deny(broken_intra_doc_links)]
+
+extern crate intra_doc_broken;
+
+pub use intra_doc_broken::foo;
diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs
index 0278caf..81e4264 100644
--- a/src/test/rustdoc-ui/intra-link-errors.rs
+++ b/src/test/rustdoc-ui/intra-link-errors.rs
@@ -2,27 +2,27 @@
 //~^ NOTE lint level is defined
 
 // FIXME: this should say that it was skipped (maybe an allowed by default lint?)
-/// [<invalid syntax>]
+/// [invalid intra-doc syntax!!]
 
 /// [path::to::nonexistent::module]
 //~^ ERROR unresolved link
-//~| NOTE `intra_link_errors` contains no item named `path`
+//~| NOTE no item named `path` in scope
 
 /// [path::to::nonexistent::macro!]
 //~^ ERROR unresolved link
-//~| NOTE `intra_link_errors` contains no item named `path`
+//~| NOTE no item named `path` in scope
 
 /// [type@path::to::nonexistent::type]
 //~^ ERROR unresolved link
-//~| NOTE `intra_link_errors` contains no item named `path`
+//~| NOTE no item named `path` in scope
 
 /// [std::io::not::here]
 //~^ ERROR unresolved link
-//~| NOTE `io` contains no item named `not`
+//~| NOTE no item named `not` in module `io`
 
 /// [type@std::io::not::here]
 //~^ ERROR unresolved link
-//~| NOTE `io` contains no item named `not`
+//~| NOTE no item named `not` in module `io`
 
 /// [std::io::Error::x]
 //~^ ERROR unresolved link
diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr
index b63f799..31e7fc4 100644
--- a/src/test/rustdoc-ui/intra-link-errors.stderr
+++ b/src/test/rustdoc-ui/intra-link-errors.stderr
@@ -2,7 +2,7 @@
   --> $DIR/intra-link-errors.rs:7:6
    |
 LL | /// [path::to::nonexistent::module]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
    |
 note: the lint level is defined here
   --> $DIR/intra-link-errors.rs:1:9
@@ -14,25 +14,25 @@
   --> $DIR/intra-link-errors.rs:11:6
    |
 LL | /// [path::to::nonexistent::macro!]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
 
 error: unresolved link to `path::to::nonexistent::type`
   --> $DIR/intra-link-errors.rs:15:6
    |
 LL | /// [type@path::to::nonexistent::type]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
 
 error: unresolved link to `std::io::not::here`
   --> $DIR/intra-link-errors.rs:19:6
    |
 LL | /// [std::io::not::here]
-   |      ^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
+   |      ^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
 
 error: unresolved link to `std::io::not::here`
   --> $DIR/intra-link-errors.rs:23:6
    |
 LL | /// [type@std::io::not::here]
-   |      ^^^^^^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not`
+   |      ^^^^^^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
 
 error: unresolved link to `std::io::Error::x`
   --> $DIR/intra-link-errors.rs:27:6
diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.rs b/src/test/rustdoc-ui/intra-link-malformed-generics.rs
new file mode 100644
index 0000000..9c54092
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-link-malformed-generics.rs
@@ -0,0 +1,19 @@
+#![deny(broken_intra_doc_links)]
+
+//! [Vec<] //~ ERROR
+//! [Vec<Box<T] //~ ERROR
+//! [Vec<Box<T>] //~ ERROR
+//! [Vec<Box<T>>>] //~ ERROR
+//! [Vec<T>>>] //~ ERROR
+//! [<Vec] //~ ERROR
+//! [Vec::<] //~ ERROR
+//! [<T>] //~ ERROR
+//! [<invalid syntax>] //~ ERROR
+//! [Vec:<T>:new()] //~ ERROR
+//! [Vec<<T>>] //~ ERROR
+//! [Vec<>] //~ ERROR
+//! [Vec<<>>] //~ ERROR
+
+// FIXME(#74563) support UFCS
+//! [<Vec as IntoIterator>::into_iter] //~ ERROR
+//! [<Vec<T> as IntoIterator>::iter] //~ ERROR
diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.stderr b/src/test/rustdoc-ui/intra-link-malformed-generics.stderr
new file mode 100644
index 0000000..fe5d4cd
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-link-malformed-generics.stderr
@@ -0,0 +1,102 @@
+error: unresolved link to `Vec<`
+  --> $DIR/intra-link-malformed-generics.rs:3:6
+   |
+LL | //! [Vec<]
+   |      ^^^^ unbalanced angle brackets
+   |
+note: the lint level is defined here
+  --> $DIR/intra-link-malformed-generics.rs:1:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: unresolved link to `Vec<Box<T`
+  --> $DIR/intra-link-malformed-generics.rs:4:6
+   |
+LL | //! [Vec<Box<T]
+   |      ^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<Box<T>`
+  --> $DIR/intra-link-malformed-generics.rs:5:6
+   |
+LL | //! [Vec<Box<T>]
+   |      ^^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<Box<T>>>`
+  --> $DIR/intra-link-malformed-generics.rs:6:6
+   |
+LL | //! [Vec<Box<T>>>]
+   |      ^^^^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<T>>>`
+  --> $DIR/intra-link-malformed-generics.rs:7:6
+   |
+LL | //! [Vec<T>>>]
+   |      ^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `<Vec`
+  --> $DIR/intra-link-malformed-generics.rs:8:6
+   |
+LL | //! [<Vec]
+   |      ^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec::<`
+  --> $DIR/intra-link-malformed-generics.rs:9:6
+   |
+LL | //! [Vec::<]
+   |      ^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `<T>`
+  --> $DIR/intra-link-malformed-generics.rs:10:6
+   |
+LL | //! [<T>]
+   |      ^^^ missing type for generic parameters
+
+error: unresolved link to `<invalid syntax>`
+  --> $DIR/intra-link-malformed-generics.rs:11:6
+   |
+LL | //! [<invalid syntax>]
+   |      ^^^^^^^^^^^^^^^^ missing type for generic parameters
+
+error: unresolved link to `Vec:<T>:new`
+  --> $DIR/intra-link-malformed-generics.rs:12:6
+   |
+LL | //! [Vec:<T>:new()]
+   |      ^^^^^^^^^^^^^ has invalid path separator
+
+error: unresolved link to `Vec<<T>>`
+  --> $DIR/intra-link-malformed-generics.rs:13:6
+   |
+LL | //! [Vec<<T>>]
+   |      ^^^^^^^^ too many angle brackets
+
+error: unresolved link to `Vec<>`
+  --> $DIR/intra-link-malformed-generics.rs:14:6
+   |
+LL | //! [Vec<>]
+   |      ^^^^^ empty angle brackets
+
+error: unresolved link to `Vec<<>>`
+  --> $DIR/intra-link-malformed-generics.rs:15:6
+   |
+LL | //! [Vec<<>>]
+   |      ^^^^^^^ too many angle brackets
+
+error: unresolved link to `<Vec as IntoIterator>::into_iter`
+  --> $DIR/intra-link-malformed-generics.rs:18:6
+   |
+LL | //! [<Vec as IntoIterator>::into_iter]
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
+   |
+   = note: see https://github.com/rust-lang/rust/issues/74563 for more information
+
+error: unresolved link to `<Vec<T> as IntoIterator>::iter`
+  --> $DIR/intra-link-malformed-generics.rs:19:6
+   |
+LL | //! [<Vec<T> as IntoIterator>::iter]
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
+   |
+   = note: see https://github.com/rust-lang/rust/issues/74563 for more information
+
+error: aborting due to 15 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
index d946aa9..d8afa9e 100644
--- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
+++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
@@ -2,7 +2,7 @@
   --> $DIR/intra-link-span-ice-55723.rs:9:10
    |
 LL | /// (arr[i])
-   |           ^ the module `intra_link_span_ice_55723` contains no item named `i`
+   |           ^ no item named `i` in scope
    |
 note: the lint level is defined here
   --> $DIR/intra-link-span-ice-55723.rs:1:9
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-links-ambiguity.rs
index d1597cd..f634353 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.rs
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.rs
@@ -34,3 +34,7 @@
 ///
 /// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar`
 pub struct Docs {}
+
+/// [true] //~ ERROR `true` is both a module and a builtin type
+/// [primitive@true]
+pub mod r#true {}
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
index 17891ca..21b92a9 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
@@ -82,5 +82,20 @@
 LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
    |                                          ^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: `true` is both a module and a builtin type
+  --> $DIR/intra-links-ambiguity.rs:38:6
+   |
+LL | /// [true]
+   |      ^^^^ ambiguous link
+   |
+help: to link to the module, prefix with `mod@`
+   |
+LL | /// [mod@true]
+   |      ^^^^^^^^
+help: to link to the builtin type, prefix with `prim@`
+   |
+LL | /// [prim@true]
+   |      ^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr
index 76a2ac0..67c4837 100644
--- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr
@@ -2,7 +2,7 @@
   --> $DIR/intra-links-warning-crlf.rs:7:6
    |
 LL | /// [error]
-   |      ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
+   |      ^^^^^ no item named `error` in scope
    |
    = note: `#[warn(broken_intra_doc_links)]` on by default
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
@@ -11,7 +11,7 @@
   --> $DIR/intra-links-warning-crlf.rs:12:11
    |
 LL | /// docs [error1]
-   |           ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error1`
+   |           ^^^^^^ no item named `error1` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -19,7 +19,7 @@
   --> $DIR/intra-links-warning-crlf.rs:15:11
    |
 LL | /// docs [error2]
-   |           ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error2`
+   |           ^^^^^^ no item named `error2` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -27,7 +27,7 @@
   --> $DIR/intra-links-warning-crlf.rs:23:20
    |
 LL |  * It also has an [error].
-   |                    ^^^^^ the module `intra_links_warning_crlf` contains no item named `error`
+   |                    ^^^^^ no item named `error` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr
index 09db465..4cdb8bb 100644
--- a/src/test/rustdoc-ui/intra-links-warning.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning.stderr
@@ -10,37 +10,37 @@
   --> $DIR/intra-links-warning.rs:3:35
    |
 LL |        //! Test with [Foo::baz], [Bar::foo], ...
-   |                                   ^^^^^^^^ the module `intra_links_warning` contains no item named `Bar`
+   |                                   ^^^^^^^^ no item named `Bar` in scope
 
 warning: unresolved link to `Uniooon::X`
   --> $DIR/intra-links-warning.rs:6:13
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
-   |             ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
+   |             ^^^^^^^^^^ no item named `Uniooon` in scope
 
 warning: unresolved link to `Qux::Z`
   --> $DIR/intra-links-warning.rs:6:30
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
-   |                              ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
+   |                              ^^^^^^ no item named `Qux` in scope
 
 warning: unresolved link to `Uniooon::X`
   --> $DIR/intra-links-warning.rs:10:14
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
-   |              ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon`
+   |              ^^^^^^^^^^ no item named `Uniooon` in scope
 
 warning: unresolved link to `Qux::Z`
   --> $DIR/intra-links-warning.rs:10:31
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
-   |                               ^^^^^^ the module `intra_links_warning` contains no item named `Qux`
+   |                               ^^^^^^ no item named `Qux` in scope
 
 warning: unresolved link to `Qux:Y`
   --> $DIR/intra-links-warning.rs:14:13
    |
 LL |        /// [Qux:Y]
-   |             ^^^^^ the module `intra_links_warning` contains no item named `Qux:Y`
+   |             ^^^^^ no item named `Qux:Y` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -48,7 +48,7 @@
   --> $DIR/intra-links-warning.rs:58:30
    |
 LL |  * time to introduce a link [error]*/
-   |                              ^^^^^ the module `intra_links_warning` contains no item named `error`
+   |                              ^^^^^ no item named `error` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -56,7 +56,7 @@
   --> $DIR/intra-links-warning.rs:64:30
    |
 LL |  * time to introduce a link [error]
-   |                              ^^^^^ the module `intra_links_warning` contains no item named `error`
+   |                              ^^^^^ no item named `error` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -70,7 +70,7 @@
            
            single line [error]
                         ^^^^^
-   = note: the module `intra_links_warning` contains no item named `error`
+   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
@@ -83,7 +83,7 @@
            
            single line with "escaping" [error]
                                         ^^^^^
-   = note: the module `intra_links_warning` contains no item named `error`
+   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
@@ -98,14 +98,14 @@
            
            [error]
             ^^^^^
-   = note: the module `intra_links_warning` contains no item named `error`
+   = note: no item named `error` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error1`
   --> $DIR/intra-links-warning.rs:80:11
    |
 LL | /// docs [error1]
-   |           ^^^^^^ the module `intra_links_warning` contains no item named `error1`
+   |           ^^^^^^ no item named `error1` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -113,7 +113,7 @@
   --> $DIR/intra-links-warning.rs:82:11
    |
 LL | /// docs [error2]
-   |           ^^^^^^ the module `intra_links_warning` contains no item named `error2`
+   |           ^^^^^^ no item named `error2` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -121,7 +121,7 @@
   --> $DIR/intra-links-warning.rs:21:10
    |
 LL | /// bar [BarA] bar
-   |          ^^^^ the module `intra_links_warning` contains no item named `BarA`
+   |          ^^^^ no item named `BarA` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -129,7 +129,7 @@
   --> $DIR/intra-links-warning.rs:27:9
    |
 LL |  * bar [BarB] bar
-   |         ^^^^ the module `intra_links_warning` contains no item named `BarB`
+   |         ^^^^ no item named `BarB` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -137,7 +137,7 @@
   --> $DIR/intra-links-warning.rs:34:6
    |
 LL | bar [BarC] bar
-   |      ^^^^ the module `intra_links_warning` contains no item named `BarC`
+   |      ^^^^ no item named `BarC` in scope
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
@@ -151,7 +151,7 @@
            
            bar [BarD] bar
                 ^^^^
-   = note: the module `intra_links_warning` contains no item named `BarD`
+   = note: no item named `BarD` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarF`
@@ -167,7 +167,7 @@
            
            bar [BarF] bar
                 ^^^^
-   = note: the module `intra_links_warning` contains no item named `BarF`
+   = note: no item named `BarF` in scope
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs
new file mode 100644
index 0000000..56ca7e7
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-tags.rs
@@ -0,0 +1,89 @@
+#![deny(invalid_html_tags)]
+
+//! <p>💩<p>
+//~^ ERROR unclosed HTML tag `p`
+//~^^ ERROR unclosed HTML tag `p`
+
+/// <img><input>
+/// <script>
+/// <img><input>
+/// </script>
+/// <unknown>
+//~^ ERROR unclosed HTML tag `unknown`
+/// < ok
+/// <script>
+//~^ ERROR unclosed HTML tag `script`
+pub fn foo() {}
+
+/// <h1>
+///   <h2>
+//~^ ERROR unclosed HTML tag `h2`
+///     <h3>
+//~^ ERROR unclosed HTML tag `h3`
+/// </h1>
+/// </hello>
+//~^ ERROR unopened HTML tag `hello`
+pub fn bar() {}
+
+/// <div>
+///    <br/> <p>
+//~^ ERROR unclosed HTML tag `p`
+/// </div>
+pub fn a() {}
+
+/// <div>
+///   <p>
+///      <div></div>
+///   </p>
+/// </div>
+pub fn b() {}
+
+/// <div style="hello">
+//~^ ERROR unclosed HTML tag `div`
+///   <h3>
+//~^ ERROR unclosed HTML tag `h3`
+/// <script
+//~^ ERROR unclosed HTML tag `script`
+pub fn c() {}
+
+// Unclosed tags shouldn't warn if they are nested inside a <script> elem.
+/// <script>
+///   <h3><div>
+/// </script>
+/// <script>
+///   <div>
+///     <p>
+///   </div>
+/// </script>
+pub fn d() {}
+
+// Unclosed tags shouldn't warn if they are nested inside a <style> elem.
+/// <style>
+///   <h3><div>
+/// </style>
+/// <stYle>
+///   <div>
+///     <p>
+///   </div>
+/// </style>
+pub fn e() {}
+
+// Closing tags need to have ">" at the end, otherwise it's not a closing tag!
+/// <div></div >
+/// <div></div
+//~^ ERROR unclosed HTML tag `div`
+pub fn f() {}
+
+/// <!---->
+/// <!-- -->
+/// <!-- <div> -->
+/// <!-- <!-- -->
+pub fn g() {}
+
+/// <!--
+/// -->
+pub fn h() {}
+
+/// <!--
+//~^ ERROR Unclosed HTML comment
+pub fn i() {}
diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr
new file mode 100644
index 0000000..aa9ace0
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-tags.stderr
@@ -0,0 +1,86 @@
+error: unclosed HTML tag `p`
+  --> $DIR/invalid-html-tags.rs:3:5
+   |
+LL | //! <p>💩<p>
+   |     ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/invalid-html-tags.rs:1:9
+   |
+LL | #![deny(invalid_html_tags)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: unclosed HTML tag `p`
+  --> $DIR/invalid-html-tags.rs:3:9
+   |
+LL | //! <p>💩<p>
+   |          ^^^
+
+error: unclosed HTML tag `unknown`
+  --> $DIR/invalid-html-tags.rs:11:5
+   |
+LL | /// <unknown>
+   |     ^^^^^^^^^
+
+error: unclosed HTML tag `script`
+  --> $DIR/invalid-html-tags.rs:14:5
+   |
+LL | /// <script>
+   |     ^^^^^^^^
+
+error: unclosed HTML tag `h2`
+  --> $DIR/invalid-html-tags.rs:19:7
+   |
+LL | ///   <h2>
+   |       ^^^^
+
+error: unclosed HTML tag `h3`
+  --> $DIR/invalid-html-tags.rs:21:9
+   |
+LL | ///     <h3>
+   |         ^^^^
+
+error: unopened HTML tag `hello`
+  --> $DIR/invalid-html-tags.rs:24:5
+   |
+LL | /// </hello>
+   |     ^^^^^^^^
+
+error: unclosed HTML tag `p`
+  --> $DIR/invalid-html-tags.rs:29:14
+   |
+LL | ///    <br/> <p>
+   |              ^^^
+
+error: unclosed HTML tag `div`
+  --> $DIR/invalid-html-tags.rs:41:5
+   |
+LL | /// <div style="hello">
+   |     ^^^^
+
+error: unclosed HTML tag `h3`
+  --> $DIR/invalid-html-tags.rs:43:7
+   |
+LL | ///   <h3>
+   |       ^^^^
+
+error: unclosed HTML tag `script`
+  --> $DIR/invalid-html-tags.rs:45:5
+   |
+LL | /// <script
+   |     ^^^^^^
+
+error: unclosed HTML tag `div`
+  --> $DIR/invalid-html-tags.rs:73:5
+   |
+LL | /// <div></div
+   |     ^^^^^
+
+error: Unclosed HTML comment
+  --> $DIR/invalid-html-tags.rs:87:5
+   |
+LL | /// <!--
+   |     ^^^
+
+error: aborting due to 13 previous errors
+
diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs
index e58c8b1..1446f7f 100644
--- a/src/test/rustdoc-ui/lint-group.rs
+++ b/src/test/rustdoc-ui/lint-group.rs
@@ -22,3 +22,8 @@
 /// println!("sup");
 /// ```
 fn private_doctest() {} //~^^^^^ ERROR documentation test in private item
+
+/// <unknown>
+//~^ ERROR unclosed HTML tag `unknown`
+//~^^ ERROR missing code example
+pub fn c() {}
diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr
index 4e9134e..0c111a3 100644
--- a/src/test/rustdoc-ui/lint-group.stderr
+++ b/src/test/rustdoc-ui/lint-group.stderr
@@ -28,11 +28,17 @@
    |         ^^^^^^^
    = note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]`
 
+error: missing code example in this documentation
+  --> $DIR/lint-group.rs:26:1
+   |
+LL | /// <unknown>
+   | ^^^^^^^^^^^^^
+
 error: unresolved link to `error`
   --> $DIR/lint-group.rs:9:29
    |
 LL | /// what up, let's make an [error]
-   |                             ^^^^^ the module `lint_group` contains no item named `error`
+   |                             ^^^^^ no item named `error` in scope
    |
 note: the lint level is defined here
   --> $DIR/lint-group.rs:7:9
@@ -42,5 +48,18 @@
    = note: `#[deny(broken_intra_doc_links)]` implied by `#[deny(rustdoc)]`
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-error: aborting due to 3 previous errors
+error: unclosed HTML tag `unknown`
+  --> $DIR/lint-group.rs:26:5
+   |
+LL | /// <unknown>
+   |     ^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-group.rs:7:9
+   |
+LL | #![deny(rustdoc)]
+   |         ^^^^^^^
+   = note: `#[deny(invalid_html_tags)]` implied by `#[deny(rustdoc)]`
+
+error: aborting due to 5 previous errors
 
diff --git a/src/test/rustdoc-ui/pub-export-lint.rs b/src/test/rustdoc-ui/pub-export-lint.rs
new file mode 100644
index 0000000..3fd3f77
--- /dev/null
+++ b/src/test/rustdoc-ui/pub-export-lint.rs
@@ -0,0 +1,5 @@
+#![deny(broken_intra_doc_links)]
+
+/// [aloha]
+//~^ ERROR unresolved link to `aloha`
+pub use std::task::RawWakerVTable;
diff --git a/src/test/rustdoc-ui/pub-export-lint.stderr b/src/test/rustdoc-ui/pub-export-lint.stderr
new file mode 100644
index 0000000..c345def
--- /dev/null
+++ b/src/test/rustdoc-ui/pub-export-lint.stderr
@@ -0,0 +1,15 @@
+error: unresolved link to `aloha`
+  --> $DIR/pub-export-lint.rs:3:6
+   |
+LL | /// [aloha]
+   |      ^^^^^ no item named `aloha` in scope
+   |
+note: the lint level is defined here
+  --> $DIR/pub-export-lint.rs:1:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs
new file mode 100644
index 0000000..a37848e
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs
@@ -0,0 +1,5 @@
+#![crate_name = "inner"]
+
+/// Links to [crate::g]
+pub fn f() {}
+pub fn g() {}
diff --git a/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs
new file mode 100644
index 0000000..fc51995
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs
@@ -0,0 +1,6 @@
+#![crate_name = "inner"]
+
+/// Links to [f()]
+pub struct Inner;
+
+pub fn f() {}
diff --git a/src/test/rustdoc/auxiliary/reexport-check.rs b/src/test/rustdoc/auxiliary/reexport-check.rs
new file mode 100644
index 0000000..672ccb1
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/reexport-check.rs
@@ -0,0 +1,2 @@
+/// Docs in original
+pub struct S;
diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs
new file mode 100644
index 0000000..633df66
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-simplification.rs
@@ -0,0 +1,182 @@
+#![crate_name = "globuliferous"]
+#![feature(doc_cfg)]
+
+// @has 'globuliferous/index.html'
+// @count   - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' '^ratel$'
+
+// @has 'globuliferous/ratel/index.html'
+// @count   - '//*[@class="stab portability"]' 8
+// @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+// @matches - '//*[@class="stab portability"]' '^zoonosology$'
+// @matches - '//*[@class="stab portability"]' '^yusho$'
+// @matches - '//*[@class="stab portability"]' '^nunciative$'
+// @matches - '//*[@class="stab portability"]' '^thionic$'
+// @matches - '//*[@class="stab portability"]' '^zincic$'
+// @matches - '//*[@class="stab portability"]' '^cosmotellurian$'
+// @matches - '//*[@class="stab portability"]' '^aposiopesis$'
+#[doc(cfg(feature = "ratel"))]
+pub mod ratel {
+    // @has 'globuliferous/ratel/fn.ovicide.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub fn ovicide() {}
+
+    // @has 'globuliferous/ratel/fn.zoonosology.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and zoonosology'
+    #[doc(cfg(feature = "zoonosology"))]
+    pub fn zoonosology() {}
+
+    // @has 'globuliferous/ratel/constant.DIAGRAPHICS.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub const DIAGRAPHICS: () = ();
+
+    // @has 'globuliferous/ratel/constant.YUSHO.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and yusho'
+    #[doc(cfg(feature = "yusho"))]
+    pub const YUSHO: () = ();
+
+    // @has 'globuliferous/ratel/static.KEYBUGLE.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub static KEYBUGLE: () = ();
+
+    // @has 'globuliferous/ratel/static.NUNCIATIVE.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and nunciative'
+    #[doc(cfg(feature = "nunciative"))]
+    pub static NUNCIATIVE: () = ();
+
+    // @has 'globuliferous/ratel/type.Wrick.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub type Wrick = ();
+
+    // @has 'globuliferous/ratel/type.Thionic.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and thionic'
+    #[doc(cfg(feature = "thionic"))]
+    pub type Thionic = ();
+
+    // @has 'globuliferous/ratel/struct.Eventration.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub struct Eventration;
+
+    // @has 'globuliferous/ratel/struct.Zincic.html'
+    // @count   - '//*[@class="stab portability"]' 2
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and zincic'
+    // @matches - '//*[@class="stab portability"]' 'crate feature rutherford'
+    #[doc(cfg(feature = "zincic"))]
+    pub struct Zincic {
+        pub rectigrade: (),
+
+        #[doc(cfg(feature = "rutherford"))]
+        pub rutherford: (),
+    }
+
+    // @has 'globuliferous/ratel/enum.Cosmotellurian.html'
+    // @count   - '//*[@class="stab portability"]' 10
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and cosmotellurian'
+    // @matches - '//*[@class="stab portability"]' 'crate feature biotaxy'
+    // @matches - '//*[@class="stab portability"]' 'crate feature xiphopagus'
+    // @matches - '//*[@class="stab portability"]' 'crate feature juxtapositive'
+    // @matches - '//*[@class="stab portability"]' 'crate feature fuero'
+    // @matches - '//*[@class="stab portability"]' 'crate feature palaeophile'
+    // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth'
+    // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and xanthocomic'
+    // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth'
+    // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and whosoever'
+    #[doc(cfg(feature = "cosmotellurian"))]
+    pub enum Cosmotellurian {
+        Groundsel {
+            jagger: (),
+
+            #[doc(cfg(feature = "xiphopagus"))]
+            xiphopagus: (),
+        },
+
+        #[doc(cfg(feature = "biotaxy"))]
+        Biotaxy {
+            glossography: (),
+
+            #[doc(cfg(feature = "juxtapositive"))]
+            juxtapositive: (),
+        },
+    }
+
+    impl Cosmotellurian {
+        pub fn uxoricide() {}
+
+        #[doc(cfg(feature = "fuero"))]
+        pub fn fuero() {}
+
+        pub const MAMELLE: () = ();
+
+        #[doc(cfg(feature = "palaeophile"))]
+        pub const PALAEOPHILE: () = ();
+    }
+
+    #[doc(cfg(feature = "broadcloth"))]
+    impl Cosmotellurian {
+        pub fn trabeculated() {}
+
+        #[doc(cfg(feature = "xanthocomic"))]
+        pub fn xanthocomic() {}
+
+        pub const BRACHIFEROUS: () = ();
+
+        #[doc(cfg(feature = "whosoever"))]
+        pub const WHOSOEVER: () = ();
+    }
+
+    // @has 'globuliferous/ratel/trait.Gnotobiology.html'
+    // @count   - '//*[@class="stab portability"]' 4
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    // @matches - '//*[@class="stab portability"]' 'crate feature unzymotic'
+    // @matches - '//*[@class="stab portability"]' 'crate feature summate'
+    // @matches - '//*[@class="stab portability"]' 'crate feature unctuous'
+    pub trait Gnotobiology {
+        const XYLOTHERAPY: ();
+
+        #[doc(cfg(feature = "unzymotic"))]
+        const UNZYMOTIC: ();
+
+        type Lepadoid;
+
+        #[doc(cfg(feature = "summate"))]
+        type Summate;
+
+        fn decalcomania();
+
+        #[doc(cfg(feature = "unctuous"))]
+        fn unctuous();
+    }
+
+    // @has 'globuliferous/ratel/trait.Aposiopesis.html'
+    // @count   - '//*[@class="stab portability"]' 4
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and aposiopesis'
+    // @matches - '//*[@class="stab portability"]' 'crate feature umbracious'
+    // @matches - '//*[@class="stab portability"]' 'crate feature uakari'
+    // @matches - '//*[@class="stab portability"]' 'crate feature rotograph'
+    #[doc(cfg(feature = "aposiopesis"))]
+    pub trait Aposiopesis {
+        const REDHIBITION: ();
+
+        #[doc(cfg(feature = "umbracious"))]
+        const UMBRACIOUS: ();
+
+        type Ophthalmoscope;
+
+        #[doc(cfg(feature = "uakari"))]
+        type Uakari;
+
+        fn meseems();
+
+        #[doc(cfg(feature = "rotograph"))]
+        fn rotograph();
+    }
+}
diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs
index aa407b7..d7041ee 100644
--- a/src/test/rustdoc/doc-cfg.rs
+++ b/src/test/rustdoc/doc-cfg.rs
@@ -10,9 +10,8 @@
 // @has doc_cfg/unix_only/index.html \
 //  '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \
 //  'This is supported on Unix only.'
-// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix\Z'
-// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix and ARM\Z'
-// @count - '//*[@class="stab portability"]' 3
+// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AARM\Z'
+// @count - '//*[@class="stab portability"]' 2
 #[doc(cfg(unix))]
 pub mod unix_only {
     // @has doc_cfg/unix_only/fn.unix_only_function.html \
@@ -26,7 +25,7 @@
     // @has doc_cfg/unix_only/trait.ArmOnly.html \
     //  '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \
     //  'This is supported on Unix and ARM only.'
-    // @count - '//*[@class="stab portability"]' 3
+    // @count - '//*[@class="stab portability"]' 2
     #[doc(cfg(target_arch = "arm"))]
     pub trait ArmOnly {
         fn unix_and_arm_only_function();
diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs
index 47ba362..7b938af 100644
--- a/src/test/rustdoc/duplicate-cfg.rs
+++ b/src/test/rustdoc/duplicate-cfg.rs
@@ -14,45 +14,41 @@
 pub struct Foo;
 
 // @has 'foo/bar/index.html'
-// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$'
-// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only'
-
-// @has 'foo/bar/struct.Bar.html'
 // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
 #[doc(cfg(feature = "sync"))]
 pub mod bar {
+    // @has 'foo/bar/struct.Bar.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
     #[doc(cfg(feature = "sync"))]
     pub struct Bar;
 }
 
 // @has 'foo/baz/index.html'
-// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$'
-// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only'
-
-// @has 'foo/baz/struct.Baz.html'
 // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
 #[doc(cfg(all(feature = "sync", feature = "send")))]
 pub mod baz {
+    // @has 'foo/baz/struct.Baz.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
     #[doc(cfg(feature = "sync"))]
     pub struct Baz;
 }
 
-// @has 'foo/qux/struct.Qux.html'
-// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
+// @has 'foo/qux/index.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
 #[doc(cfg(feature = "sync"))]
 pub mod qux {
+    // @has 'foo/qux/struct.Qux.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
     #[doc(cfg(all(feature = "sync", feature = "send")))]
     pub struct Qux;
 }
 
 // @has 'foo/quux/index.html'
-// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$'
-// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only'
-
-// @has 'foo/quux/struct.Quux.html'
-// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo only.'
 #[doc(cfg(all(feature = "sync", feature = "send", foo)))]
 pub mod quux {
+    // @has 'foo/quux/struct.Quux.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.'
     #[doc(cfg(all(feature = "send", feature = "sync", bar)))]
     pub struct Quux;
 }
diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc-link-generic-params.rs
new file mode 100644
index 0000000..7d72894
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-link-generic-params.rs
@@ -0,0 +1,59 @@
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
+//! Here's a link to [`Iterator<Box<T>>::Item`].
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+
+//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+
+//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
+
+//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
+//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
+//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+
+//! This is also pretty tricky: [`TypeId::of::<String>()`].
+//! And this too: [`Vec::<std::error::Error>::len`].
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+
+//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
+//! [`Box::<T>new()`]. We may not support them in the future!
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+
+//! These will be resolved as regular links:
+//! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
+//! - [`this is <invalid syntax> twice`]
+//! - [`<invalid syntax> thrice`](https://www.rust-lang.org)
+//! - [`<invalid syntax> four times`][rlo]
+//! - [a < b][rlo]
+//! - [c > d]
+//!
+//! [`this is <invalid syntax> twice`]: https://www.rust-lang.org
+//! [rlo]: https://www.rust-lang.org
+//! [c > d]: https://www.rust-lang.org
+//!
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> first'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> twice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> thrice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> four times'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'a < b'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'c > d'
+
+use std::any::TypeId;
diff --git a/src/test/rustdoc/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-link-cross-crate-crate.rs
new file mode 100644
index 0000000..edf5447
--- /dev/null
+++ b/src/test/rustdoc/intra-link-cross-crate-crate.rs
@@ -0,0 +1,6 @@
+// aux-build:intra-link-cross-crate-crate.rs
+// build-aux-docs
+#![crate_name = "outer"]
+extern crate inner;
+// @has outer/fn.f.html '//a[@href="../inner/fn.g.html"]' "crate::g"
+pub use inner::f;
diff --git a/src/test/rustdoc/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-link-reexport-additional-docs.rs
new file mode 100644
index 0000000..96f3580
--- /dev/null
+++ b/src/test/rustdoc/intra-link-reexport-additional-docs.rs
@@ -0,0 +1,23 @@
+// aux-build:intra-link-reexport-additional-docs.rs
+// build-aux-docs
+#![crate_name = "foo"]
+extern crate inner;
+
+// @has foo/struct.Inner.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code'
+/// [crate::with_code]
+// @has - '//a[@href="../foo/fn.with_code.html"]' 'different text'
+/// [different text][with_code]
+// @has - '//a[@href="../foo/fn.me_too.html"]' 'me_too'
+#[doc = "[me_too]"]
+// @has - '//a[@href="../foo/fn.me_three.html"]' 'reference link'
+/// This [reference link]
+#[doc = "has an attr in the way"]
+///
+/// [reference link]: me_three
+// Should still resolve links from the original module in that scope
+// @has - '//a[@href="../inner/fn.f.html"]' 'f()'
+pub use inner::Inner;
+
+pub fn with_code() {}
+pub fn me_too() {}
+pub fn me_three() {}
diff --git a/src/test/rustdoc/no-compiler-reexport.rs b/src/test/rustdoc/no-compiler-reexport.rs
new file mode 100644
index 0000000..6d50325
--- /dev/null
+++ b/src/test/rustdoc/no-compiler-reexport.rs
@@ -0,0 +1,7 @@
+// compile-flags: --no-defaults
+
+#![crate_name = "foo"]
+
+// @has 'foo/index.html' '//code' 'extern crate std;'
+// @!has 'foo/index.html' '//code' 'use std::prelude::v1::*;'
+pub struct Foo;
diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs
index 8f69b89..3041ff7 100644
--- a/src/test/rustdoc/primitive-link.rs
+++ b/src/test/rustdoc/primitive-link.rs
@@ -7,8 +7,7 @@
 // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32'
 // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str'
 
-// FIXME: this doesn't resolve
-// @ has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
 
 /// It contains [`u32`] and [i64].
 /// It also links to [std::primitive::i32], [std::primitive::str],
diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs
new file mode 100644
index 0000000..066b0cf
--- /dev/null
+++ b/src/test/rustdoc/reexport-check.rs
@@ -0,0 +1,17 @@
+// aux-build:reexport-check.rs
+#![crate_name = "foo"]
+
+extern crate reexport_check;
+
+// @!has 'foo/index.html' '//code' 'pub use self::i32;'
+// @has 'foo/index.html' '//tr[@class="module-item"]' 'i32'
+// @has 'foo/i32/index.html'
+pub use std::i32;
+// @!has 'foo/index.html' '//code' 'pub use self::string::String;'
+// @has 'foo/index.html' '//tr[@class="module-item"]' 'String'
+pub use std::string::String;
+
+// @has 'foo/index.html' '//td[@class="docblock-short"]' 'Docs in original'
+// this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment
+#[doc(inline)]
+pub use reexport_check::S;
diff --git a/src/test/rustdoc/static.rs b/src/test/rustdoc/static.rs
new file mode 100644
index 0000000..90dafd8
--- /dev/null
+++ b/src/test/rustdoc/static.rs
@@ -0,0 +1,12 @@
+// compile-flags: --document-private-items
+
+#![crate_type = "lib"]
+
+// @has static/static.FOO.html '//pre' 'static FOO: usize'
+static FOO: usize = 1;
+
+// @has static/static.BAR.html '//pre' 'pub static BAR: usize'
+pub static BAR: usize = 1;
+
+// @has static/static.BAZ.html '//pre' 'pub static mut BAZ: usize'
+pub static mut BAZ: usize = 1;
diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs
index e97dcab..a9520b5 100644
--- a/src/test/ui-fulldeps/compiler-calls.rs
+++ b/src/test/ui-fulldeps/compiler-calls.rs
@@ -26,7 +26,8 @@
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
     rustc_driver::catch_fatal_errors(|| {
-        rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok();
-    }).ok();
+        rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run().ok();
+    })
+    .ok();
     assert_eq!(count, 2);
 }
diff --git a/src/test/ui/allocator/auxiliary/helper.rs b/src/test/ui/allocator/auxiliary/helper.rs
index 7f6770c..008fb35 100644
--- a/src/test/ui/allocator/auxiliary/helper.rs
+++ b/src/test/ui/allocator/auxiliary/helper.rs
@@ -1,8 +1,10 @@
 // no-prefer-dynamic
 
 #![crate_type = "rlib"]
+#![no_std]
 
-use std::fmt;
+extern crate alloc;
+use alloc::fmt;
 
 pub fn work_with(p: &fmt::Debug) {
     drop(p);
diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
new file mode 100644
index 0000000..f09fafb
--- /dev/null
+++ b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
@@ -0,0 +1,97 @@
+// run-pass
+// ignore-android no libc
+// ignore-cloudabi no libc
+// ignore-emscripten no libc
+// ignore-sgx no libc
+// ignore-wasm32 no libc
+// only-linux
+// compile-flags:-C panic=abort
+// aux-build:helper.rs
+
+#![feature(start, rustc_private, new_uninit, panic_info_message)]
+#![feature(alloc_error_handler)]
+#![no_std]
+
+extern crate alloc;
+extern crate libc;
+
+// ARM targets need these symbols
+#[no_mangle]
+pub fn __aeabi_unwind_cpp_pr0() {}
+
+#[no_mangle]
+pub fn __aeabi_unwind_cpp_pr1() {}
+
+use core::ptr::null_mut;
+use core::alloc::{GlobalAlloc, Layout};
+use alloc::boxed::Box;
+
+extern crate helper;
+
+struct MyAllocator;
+
+#[alloc_error_handler]
+fn my_oom(layout: Layout) -> !
+{
+    use alloc::fmt::write;
+    unsafe {
+        let size = layout.size();
+        let mut s = alloc::string::String::new();
+        write(&mut s, format_args!("My OOM: failed to allocate {} bytes!\n", size)).unwrap();
+        let s = s.as_str();
+        libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
+        libc::exit(0)
+    }
+}
+
+unsafe impl GlobalAlloc for MyAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        if layout.size() < 4096 {
+            libc::malloc(layout.size()) as _
+        } else {
+            null_mut()
+        }
+    }
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+}
+
+#[global_allocator]
+static A: MyAllocator = MyAllocator;
+
+#[panic_handler]
+fn panic(panic_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
+            const PSTR: &str = "panic occurred: ";
+            const CR: &str = "\n";
+            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
+            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
+            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
+        }
+        if let Some(args) = panic_info.message() {
+            let mut s = alloc::string::String::new();
+            alloc::fmt::write(&mut s, *args).unwrap();
+            let s = s.as_str();
+            const PSTR: &str = "panic occurred: ";
+            const CR: &str = "\n";
+            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
+            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
+            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
+        } else {
+            const PSTR: &str = "panic occurred\n";
+            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
+        }
+        libc::exit(1)
+    }
+}
+
+#[derive(Debug)]
+struct Page([[u64; 32]; 16]);
+
+#[start]
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let zero = Box::<Page>::new_zeroed();
+    let zero = unsafe { zero.assume_init() };
+    helper::work_with(&zero);
+    1
+}
diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
new file mode 100644
index 0000000..4d68160
--- /dev/null
+++ b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
@@ -0,0 +1,84 @@
+// run-pass
+// ignore-android no libc
+// ignore-cloudabi no libc
+// ignore-emscripten no libc
+// ignore-sgx no libc
+// ignore-wasm32 no libc
+// only-linux
+// compile-flags:-C panic=abort
+// aux-build:helper.rs
+// gate-test-default_alloc_error_handler
+
+#![feature(start, rustc_private, new_uninit, panic_info_message)]
+#![feature(default_alloc_error_handler)]
+#![no_std]
+
+extern crate alloc;
+extern crate libc;
+
+// ARM targets need these symbols
+#[no_mangle]
+pub fn __aeabi_unwind_cpp_pr0() {}
+
+#[no_mangle]
+pub fn __aeabi_unwind_cpp_pr1() {}
+
+use alloc::boxed::Box;
+use core::alloc::{GlobalAlloc, Layout};
+use core::ptr::null_mut;
+
+extern crate helper;
+
+struct MyAllocator;
+
+unsafe impl GlobalAlloc for MyAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        if layout.size() < 4096 {
+            libc::malloc(layout.size()) as _
+        } else {
+            null_mut()
+        }
+    }
+    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+}
+
+#[global_allocator]
+static A: MyAllocator = MyAllocator;
+
+#[panic_handler]
+fn panic(panic_info: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
+            const PSTR: &str = "panic occurred: ";
+            const CR: &str = "\n";
+            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
+            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
+            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
+        }
+        if let Some(args) = panic_info.message() {
+            let mut s = alloc::string::String::new();
+            alloc::fmt::write(&mut s, *args).unwrap();
+            let s = s.as_str();
+            const PSTR: &str = "panic occurred: ";
+            const CR: &str = "\n";
+            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
+            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
+            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
+        } else {
+            const PSTR: &str = "panic occurred\n";
+            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
+        }
+        libc::exit(0)
+    }
+}
+
+#[derive(Debug)]
+struct Page([[u64; 32]; 16]);
+
+#[start]
+pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let zero = Box::<Page>::new_zeroed();
+    let zero = unsafe { zero.assume_init() };
+    helper::work_with(&zero);
+    1
+}
diff --git a/src/test/ui/arg-count-mismatch.stderr b/src/test/ui/arg-count-mismatch.stderr
index 7bc0613..d0577e4 100644
--- a/src/test/ui/arg-count-mismatch.stderr
+++ b/src/test/ui/arg-count-mismatch.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/arg-count-mismatch.rs:5:28
    |
-LL | fn f(x: isize) { }
-   | -------------- defined here
-LL | 
 LL | fn main() { let i: (); i = f(); }
    |                            ^-- supplied 0 arguments
    |                            |
    |                            expected 1 argument
+   |
+note: function defined here
+  --> $DIR/arg-count-mismatch.rs:3:4
+   |
+LL | fn f(x: isize) { }
+   |    ^ --------
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/array-slice-vec/arr_cycle.rs b/src/test/ui/array-slice-vec/arr_cycle.rs
deleted file mode 100644
index c262b5a..0000000
--- a/src/test/ui/array-slice-vec/arr_cycle.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct B<'a> {
-    a: [Cell<Option<&'a B<'a>>>; 2]
-}
-
-impl<'a> B<'a> {
-    fn new() -> B<'a> {
-        B { a: [Cell::new(None), Cell::new(None)] }
-    }
-}
-
-fn f() {
-    let (b1, b2, b3);
-    b1 = B::new();
-    b2 = B::new();
-    b3 = B::new();
-    b1.a[0].set(Some(&b2));
-    b1.a[1].set(Some(&b3));
-    b2.a[0].set(Some(&b2));
-    b2.a[1].set(Some(&b3));
-    b3.a[0].set(Some(&b1));
-    b3.a[1].set(Some(&b2));
-}
-
-fn main() {
-    f();
-}
diff --git a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
index 0ad05b3..7c1a92c 100644
--- a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
+++ b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0308]: mismatched types
   --> $DIR/match_arr_unknown_len.rs:6:9
diff --git a/src/test/ui/array-slice-vec/vec-slice-drop.rs b/src/test/ui/array-slice-vec/vec-slice-drop.rs
deleted file mode 100644
index 3a9ea86..0000000
--- a/src/test/ui/array-slice-vec/vec-slice-drop.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-
-#![allow(non_camel_case_types)]
-
-use std::cell::Cell;
-
-// Make sure that destructors get run on slice literals
-struct foo<'a> {
-    x: &'a Cell<isize>,
-}
-
-impl<'a> Drop for foo<'a> {
-    fn drop(&mut self) {
-        self.x.set(self.x.get() + 1);
-    }
-}
-
-fn foo(x: &Cell<isize>) -> foo {
-    foo {
-        x: x
-    }
-}
-
-pub fn main() {
-    let x = &Cell::new(0);
-    {
-        let l = &[foo(x)];
-        assert_eq!(l[0].x.get(), 0);
-    }
-    assert_eq!(x.get(), 1);
-}
diff --git a/src/test/ui/array-slice-vec/vec_cycle.rs b/src/test/ui/array-slice-vec/vec_cycle.rs
deleted file mode 100644
index 82bce43..0000000
--- a/src/test/ui/array-slice-vec/vec_cycle.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// run-pass
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct C<'a> {
-    v: Vec<Cell<Option<&'a C<'a>>>>,
-}
-
-impl<'a> C<'a> {
-    fn new() -> C<'a> {
-        C { v: Vec::new() }
-    }
-}
-
-fn f() {
-    let (mut c1, mut c2, mut c3);
-    c1 = C::new();
-    c2 = C::new();
-    c3 = C::new();
-
-    c1.v.push(Cell::new(None));
-    c1.v.push(Cell::new(None));
-    c2.v.push(Cell::new(None));
-    c2.v.push(Cell::new(None));
-    c3.v.push(Cell::new(None));
-    c3.v.push(Cell::new(None));
-
-    c1.v[0].set(Some(&c2));
-    c1.v[1].set(Some(&c3));
-    c2.v[0].set(Some(&c2));
-    c2.v[1].set(Some(&c3));
-    c3.v[0].set(Some(&c1));
-    c3.v[1].set(Some(&c2));
-}
-
-fn main() {
-    f();
-}
diff --git a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs b/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs
deleted file mode 100644
index 1a3606d..0000000
--- a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// run-pass
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct Refs<'a> {
-    v: Vec<Cell<Option<&'a C<'a>>>>,
-}
-
-#[derive(Debug)]
-struct C<'a> {
-    refs: Refs<'a>,
-}
-
-impl<'a> Refs<'a> {
-    fn new() -> Refs<'a> {
-        Refs { v: Vec::new() }
-    }
-}
-
-impl<'a> C<'a> {
-    fn new() -> C<'a> {
-        C { refs: Refs::new() }
-    }
-}
-
-fn f() {
-    let (mut c1, mut c2, mut c3);
-    c1 = C::new();
-    c2 = C::new();
-    c3 = C::new();
-
-    c1.refs.v.push(Cell::new(None));
-    c1.refs.v.push(Cell::new(None));
-    c2.refs.v.push(Cell::new(None));
-    c2.refs.v.push(Cell::new(None));
-    c3.refs.v.push(Cell::new(None));
-    c3.refs.v.push(Cell::new(None));
-
-    c1.refs.v[0].set(Some(&c2));
-    c1.refs.v[1].set(Some(&c3));
-    c2.refs.v[0].set(Some(&c2));
-    c2.refs.v[1].set(Some(&c3));
-    c3.refs.v[0].set(Some(&c1));
-    c3.refs.v[1].set(Some(&c2));
-}
-
-fn main() {
-    f();
-}
diff --git a/src/test/ui/array_const_index-0.rs b/src/test/ui/array_const_index-0.rs
index 3422aea..4021dfc 100644
--- a/src/test/ui/array_const_index-0.rs
+++ b/src/test/ui/array_const_index-0.rs
@@ -1,6 +1,6 @@
 const A: &'static [i32] = &[];
 const B: i32 = (&A)[1];
-//~^ index out of bounds: the len is 0 but the index is 1
+//~^ index out of bounds: the length is 0 but the index is 1
 //~| ERROR any use of this value will cause an error
 
 fn main() {
diff --git a/src/test/ui/array_const_index-0.stderr b/src/test/ui/array_const_index-0.stderr
index 16ebc4a..7ccc3aa 100644
--- a/src/test/ui/array_const_index-0.stderr
+++ b/src/test/ui/array_const_index-0.stderr
@@ -4,7 +4,7 @@
 LL | const B: i32 = (&A)[1];
    | ---------------^^^^^^^-
    |                |
-   |                index out of bounds: the len is 0 but the index is 1
+   |                index out of bounds: the length is 0 but the index is 1
    |
    = note: `#[deny(const_err)]` on by default
 
diff --git a/src/test/ui/array_const_index-1.rs b/src/test/ui/array_const_index-1.rs
index 1f77cb6..d0ee179 100644
--- a/src/test/ui/array_const_index-1.rs
+++ b/src/test/ui/array_const_index-1.rs
@@ -1,6 +1,6 @@
 const A: [i32; 0] = [];
 const B: i32 = A[1];
-//~^ index out of bounds: the len is 0 but the index is 1
+//~^ index out of bounds: the length is 0 but the index is 1
 //~| ERROR any use of this value will cause an error
 
 fn main() {
diff --git a/src/test/ui/array_const_index-1.stderr b/src/test/ui/array_const_index-1.stderr
index 98a64ea..37de61b 100644
--- a/src/test/ui/array_const_index-1.stderr
+++ b/src/test/ui/array_const_index-1.stderr
@@ -4,7 +4,7 @@
 LL | const B: i32 = A[1];
    | ---------------^^^^-
    |                |
-   |                index out of bounds: the len is 0 but the index is 1
+   |                index out of bounds: the length is 0 but the index is 1
    |
    = note: `#[deny(const_err)]` on by default
 
diff --git a/src/test/ui/asm/interpolated-idents.rs b/src/test/ui/asm/interpolated-idents.rs
new file mode 100644
index 0000000..f4cb749
--- /dev/null
+++ b/src/test/ui/asm/interpolated-idents.rs
@@ -0,0 +1,24 @@
+// only-x86_64
+
+#![feature(asm)]
+
+macro_rules! m {
+    ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
+     $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
+     $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => {
+        unsafe {
+            asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+            //~^ ERROR asm outputs are not allowed with the `noreturn` option
+            const x, sym x,
+            $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+            //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+            //~| ERROR the `pure` and `noreturn` options are mutually exclusive
+        }
+    };
+}
+
+fn main() {
+    m!(in out lateout inout inlateout const sym
+       pure nomem readonly preserves_flags
+       noreturn nostack att_syntax options);
+}
diff --git a/src/test/ui/asm/interpolated-idents.stderr b/src/test/ui/asm/interpolated-idents.stderr
new file mode 100644
index 0000000..6ffe8d9
--- /dev/null
+++ b/src/test/ui/asm/interpolated-idents.stderr
@@ -0,0 +1,51 @@
+error: the `nomem` and `readonly` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `pure` and `noreturn` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm outputs are not allowed with the `noreturn` option
+  --> $DIR/interpolated-idents.rs:10:32
+   |
+LL |               asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+   |                                  ^^^^^^^^^  ^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^
+...
+LL |       m!(in out lateout inout inlateout const sym
+   |  _____-
+   | |_____|
+   | |_____|
+   | |_____|
+   | |
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |                                            -
+   | |____________________________________________|
+   | |____________________________________________in this macro invocation
+   | |____________________________________________in this macro invocation
+   | |____________________________________________in this macro invocation
+   |                                              in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/associated-const/associated-const-in-trait.stderr b/src/test/ui/associated-const/associated-const-in-trait.stderr
deleted file mode 100644
index a8a8d01..0000000
--- a/src/test/ui/associated-const/associated-const-in-trait.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0038]: the trait `Trait` cannot be made into an object
-  --> $DIR/associated-const-in-trait.rs:9:6
-   |
-LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
-LL |     const N: usize;
-   |           - ...because it contains this associated `const`
-...
-LL | impl dyn Trait {
-   |      ^^^^^^^^^ the trait `Trait` cannot be made into an object
-   |
-   = help: consider moving `N` to another trait
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr b/src/test/ui/associated-const/defaults-not-assumed-fail.stderr
deleted file mode 100644
index c1b0801..0000000
--- a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/defaults-not-assumed-fail.rs:8:19
-   |
-LL |     const B: u8 = Self::A + 1;
-   |     --------------^^^^^^^^^^^-
-   |                   |
-   |                   attempt to compute `u8::MAX + 1_u8` which would overflow
-   |
-   = note: `#[deny(const_err)]` on by default
-
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/defaults-not-assumed-fail.rs:33:5
-   |
-LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
-   |     ^^^^^^^^^^^-------------^^^^^
-   |                |
-   |                referenced constant has errors
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: erroneous constant used
-  --> $DIR/defaults-not-assumed-fail.rs:33:5
-   |
-LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr
deleted file mode 100644
index 724823e..0000000
--- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr
+++ /dev/null
@@ -1,54 +0,0 @@
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
-   |
-LL |     const NEG: i32 = -i32::MIN + T::NEG;
-   |                      ^^^^^^^^^ attempt to negate i32::MIN which would overflow
-   |
-   = note: `#[deny(arithmetic_overflow)]` on by default
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
-   |
-LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
-   |                                   ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
-   |
-LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
-   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
-   |
-LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
-   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
-   |
-LL |     const DIV: i32 = (1/0) + T::DIV;
-   |                      ^^^^^ attempt to divide 1_i32 by zero
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
-   |
-LL |     const DIV_REV: i32 = T::DIV + (1/0);
-   |                                   ^^^^^ attempt to divide 1_i32 by zero
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
-   |
-LL |     const OOB: i32 = [1][1] + T::OOB;
-   |                      ^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35
-   |
-LL |     const OOB_REV: i32 = T::OOB + [1][1];
-   |                                   ^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 8 previous errors
-
diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr
deleted file mode 100644
index 724823e..0000000
--- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr
+++ /dev/null
@@ -1,54 +0,0 @@
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
-   |
-LL |     const NEG: i32 = -i32::MIN + T::NEG;
-   |                      ^^^^^^^^^ attempt to negate i32::MIN which would overflow
-   |
-   = note: `#[deny(arithmetic_overflow)]` on by default
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
-   |
-LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
-   |                                   ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
-   |
-LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
-   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
-   |
-LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
-   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
-   |
-LL |     const DIV: i32 = (1/0) + T::DIV;
-   |                      ^^^^^ attempt to divide 1_i32 by zero
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
-   |
-LL |     const DIV_REV: i32 = T::DIV + (1/0);
-   |                                   ^^^^^ attempt to divide 1_i32 by zero
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
-   |
-LL |     const OOB: i32 = [1][1] + T::OOB;
-   |                      ^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35
-   |
-LL |     const OOB_REV: i32 = T::OOB + [1][1];
-   |                                   ^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 8 previous errors
-
diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr
deleted file mode 100644
index 724823e..0000000
--- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr
+++ /dev/null
@@ -1,54 +0,0 @@
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
-   |
-LL |     const NEG: i32 = -i32::MIN + T::NEG;
-   |                      ^^^^^^^^^ attempt to negate i32::MIN which would overflow
-   |
-   = note: `#[deny(arithmetic_overflow)]` on by default
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
-   |
-LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
-   |                                   ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
-   |
-LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
-   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
-
-error: this arithmetic operation will overflow
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
-   |
-LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
-   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
-   |
-LL |     const DIV: i32 = (1/0) + T::DIV;
-   |                      ^^^^^ attempt to divide 1_i32 by zero
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
-   |
-LL |     const DIV_REV: i32 = T::DIV + (1/0);
-   |                                   ^^^^^ attempt to divide 1_i32 by zero
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
-   |
-LL |     const OOB: i32 = [1][1] + T::OOB;
-   |                      ^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: this operation will panic at runtime
-  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35
-   |
-LL |     const OOB_REV: i32 = T::OOB + [1][1];
-   |                                   ^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 8 previous errors
-
diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.rs b/src/test/ui/associated-consts/associated-const-ambiguity-report.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-ambiguity-report.rs
rename to src/test/ui/associated-consts/associated-const-ambiguity-report.rs
diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-ambiguity-report.stderr
rename to src/test/ui/associated-consts/associated-const-ambiguity-report.stderr
diff --git a/src/test/ui/associated-const/associated-const-array-len.rs b/src/test/ui/associated-consts/associated-const-array-len.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-array-len.rs
rename to src/test/ui/associated-consts/associated-const-array-len.rs
diff --git a/src/test/ui/associated-const/associated-const-array-len.stderr b/src/test/ui/associated-consts/associated-const-array-len.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-array-len.stderr
rename to src/test/ui/associated-consts/associated-const-array-len.stderr
diff --git a/src/test/ui/associated-const/associated-const-dead-code.rs b/src/test/ui/associated-consts/associated-const-dead-code.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-dead-code.rs
rename to src/test/ui/associated-consts/associated-const-dead-code.rs
diff --git a/src/test/ui/associated-const/associated-const-dead-code.stderr b/src/test/ui/associated-consts/associated-const-dead-code.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-dead-code.stderr
rename to src/test/ui/associated-consts/associated-const-dead-code.stderr
diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.rs b/src/test/ui/associated-consts/associated-const-generic-obligations.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-generic-obligations.rs
rename to src/test/ui/associated-consts/associated-const-generic-obligations.rs
diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.stderr b/src/test/ui/associated-consts/associated-const-generic-obligations.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-generic-obligations.stderr
rename to src/test/ui/associated-consts/associated-const-generic-obligations.stderr
diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.rs b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-impl-wrong-lifetime.rs
rename to src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs
diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr b/src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr
rename to src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr
diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-type.rs b/src/test/ui/associated-consts/associated-const-impl-wrong-type.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-impl-wrong-type.rs
rename to src/test/ui/associated-consts/associated-const-impl-wrong-type.rs
diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-type.stderr b/src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-impl-wrong-type.stderr
rename to src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr
diff --git a/src/test/ui/associated-const/associated-const-in-trait.rs b/src/test/ui/associated-consts/associated-const-in-trait.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-in-trait.rs
rename to src/test/ui/associated-consts/associated-const-in-trait.rs
diff --git a/src/test/ui/associated-consts/associated-const-in-trait.stderr b/src/test/ui/associated-consts/associated-const-in-trait.stderr
new file mode 100644
index 0000000..7b45941
--- /dev/null
+++ b/src/test/ui/associated-consts/associated-const-in-trait.stderr
@@ -0,0 +1,18 @@
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/associated-const-in-trait.rs:9:6
+   |
+LL | impl dyn Trait {
+   |      ^^^^^^^^^ `Trait` cannot be made into an object
+   |
+   = help: consider moving `N` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/associated-const-in-trait.rs:6:11
+   |
+LL | trait Trait {
+   |       ----- this trait cannot be made into an object...
+LL |     const N: usize;
+   |           ^ ...because it contains this associated `const`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/associated-const/associated-const-no-item.rs b/src/test/ui/associated-consts/associated-const-no-item.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-no-item.rs
rename to src/test/ui/associated-consts/associated-const-no-item.rs
diff --git a/src/test/ui/associated-const/associated-const-no-item.stderr b/src/test/ui/associated-consts/associated-const-no-item.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-no-item.stderr
rename to src/test/ui/associated-consts/associated-const-no-item.stderr
diff --git a/src/test/ui/associated-const/associated-const-private-impl.rs b/src/test/ui/associated-consts/associated-const-private-impl.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-private-impl.rs
rename to src/test/ui/associated-consts/associated-const-private-impl.rs
diff --git a/src/test/ui/associated-const/associated-const-private-impl.stderr b/src/test/ui/associated-consts/associated-const-private-impl.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-private-impl.stderr
rename to src/test/ui/associated-consts/associated-const-private-impl.stderr
diff --git a/src/test/ui/associated-const/associated-const-trait-bound.rs b/src/test/ui/associated-consts/associated-const-trait-bound.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-trait-bound.rs
rename to src/test/ui/associated-consts/associated-const-trait-bound.rs
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arms.rs b/src/test/ui/associated-consts/associated-const-type-parameter-arms.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-type-parameter-arms.rs
rename to src/test/ui/associated-consts/associated-const-type-parameter-arms.rs
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arms.stderr b/src/test/ui/associated-consts/associated-const-type-parameter-arms.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-type-parameter-arms.stderr
rename to src/test/ui/associated-consts/associated-const-type-parameter-arms.stderr
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-type-parameter-arrays-2.rs
rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.rs
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr
rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays-2.stderr
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.rs b/src/test/ui/associated-consts/associated-const-type-parameter-arrays.rs
similarity index 100%
rename from src/test/ui/associated-const/associated-const-type-parameter-arrays.rs
rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays.rs
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr b/src/test/ui/associated-consts/associated-const-type-parameter-arrays.stderr
similarity index 100%
rename from src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr
rename to src/test/ui/associated-consts/associated-const-type-parameter-arrays.stderr
diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.rs b/src/test/ui/associated-consts/defaults-cyclic-fail.rs
similarity index 100%
rename from src/test/ui/associated-const/defaults-cyclic-fail.rs
rename to src/test/ui/associated-consts/defaults-cyclic-fail.rs
diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-consts/defaults-cyclic-fail.stderr
similarity index 100%
rename from src/test/ui/associated-const/defaults-cyclic-fail.stderr
rename to src/test/ui/associated-consts/defaults-cyclic-fail.stderr
diff --git a/src/test/ui/associated-const/defaults-cyclic-pass.rs b/src/test/ui/associated-consts/defaults-cyclic-pass.rs
similarity index 100%
rename from src/test/ui/associated-const/defaults-cyclic-pass.rs
rename to src/test/ui/associated-consts/defaults-cyclic-pass.rs
diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.rs b/src/test/ui/associated-consts/defaults-not-assumed-fail.rs
similarity index 100%
rename from src/test/ui/associated-const/defaults-not-assumed-fail.rs
rename to src/test/ui/associated-consts/defaults-not-assumed-fail.rs
diff --git a/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
new file mode 100644
index 0000000..1497633
--- /dev/null
+++ b/src/test/ui/associated-consts/defaults-not-assumed-fail.stderr
@@ -0,0 +1,31 @@
+error: any use of this value will cause an error
+  --> $DIR/defaults-not-assumed-fail.rs:8:19
+   |
+LL |     const B: u8 = Self::A + 1;
+   |     --------------^^^^^^^^^^^-
+   |                   |
+   |                   attempt to compute `u8::MAX + 1_u8`, which would overflow
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error[E0080]: evaluation of constant expression failed
+  --> $DIR/defaults-not-assumed-fail.rs:33:5
+   |
+LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
+   |     ^^^^^^^^^^^-------------^^^^^
+   |                |
+   |                referenced constant has errors
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: erroneous constant used
+  --> $DIR/defaults-not-assumed-fail.rs:33:5
+   |
+LL |     assert_eq!(<() as Tr>::B, 0);    // causes the error above
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/associated-const/defaults-not-assumed-pass.rs b/src/test/ui/associated-consts/defaults-not-assumed-pass.rs
similarity index 100%
rename from src/test/ui/associated-const/defaults-not-assumed-pass.rs
rename to src/test/ui/associated-consts/defaults-not-assumed-pass.rs
diff --git a/src/test/ui/associated-const/issue-63496.rs b/src/test/ui/associated-consts/issue-63496.rs
similarity index 100%
rename from src/test/ui/associated-const/issue-63496.rs
rename to src/test/ui/associated-consts/issue-63496.rs
diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-consts/issue-63496.stderr
similarity index 100%
rename from src/test/ui/associated-const/issue-63496.stderr
rename to src/test/ui/associated-consts/issue-63496.stderr
diff --git a/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.noopt.stderr b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.noopt.stderr
new file mode 100644
index 0000000..f59287b
--- /dev/null
+++ b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.noopt.stderr
@@ -0,0 +1,54 @@
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
+   |
+LL |     const NEG: i32 = -i32::MIN + T::NEG;
+   |                      ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow
+   |
+   = note: `#[deny(arithmetic_overflow)]` on by default
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
+   |
+LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
+   |                                   ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
+   |
+LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
+   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
+   |
+LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
+   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
+   |
+LL |     const DIV: i32 = (1/0) + T::DIV;
+   |                      ^^^^^ attempt to divide `1_i32` by zero
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
+   |
+LL |     const DIV_REV: i32 = T::DIV + (1/0);
+   |                                   ^^^^^ attempt to divide `1_i32` by zero
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
+   |
+LL |     const OOB: i32 = [1][1] + T::OOB;
+   |                      ^^^^^^ index out of bounds: the length is 1 but the index is 1
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35
+   |
+LL |     const OOB_REV: i32 = T::OOB + [1][1];
+   |                                   ^^^^^^ index out of bounds: the length is 1 but the index is 1
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt.stderr b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt.stderr
new file mode 100644
index 0000000..f59287b
--- /dev/null
+++ b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt.stderr
@@ -0,0 +1,54 @@
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
+   |
+LL |     const NEG: i32 = -i32::MIN + T::NEG;
+   |                      ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow
+   |
+   = note: `#[deny(arithmetic_overflow)]` on by default
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
+   |
+LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
+   |                                   ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
+   |
+LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
+   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
+   |
+LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
+   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
+   |
+LL |     const DIV: i32 = (1/0) + T::DIV;
+   |                      ^^^^^ attempt to divide `1_i32` by zero
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
+   |
+LL |     const DIV_REV: i32 = T::DIV + (1/0);
+   |                                   ^^^^^ attempt to divide `1_i32` by zero
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
+   |
+LL |     const OOB: i32 = [1][1] + T::OOB;
+   |                      ^^^^^^ index out of bounds: the length is 1 but the index is 1
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35
+   |
+LL |     const OOB_REV: i32 = T::OOB + [1][1];
+   |                                   ^^^^^^ index out of bounds: the length is 1 but the index is 1
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr
new file mode 100644
index 0000000..f59287b
--- /dev/null
+++ b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr
@@ -0,0 +1,54 @@
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22
+   |
+LL |     const NEG: i32 = -i32::MIN + T::NEG;
+   |                      ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow
+   |
+   = note: `#[deny(arithmetic_overflow)]` on by default
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35
+   |
+LL |     const NEG_REV: i32 = T::NEG + (-i32::MIN);
+   |                                   ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22
+   |
+LL |     const ADD: i32 = (i32::MAX+1) + T::ADD;
+   |                      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
+
+error: this arithmetic operation will overflow
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36
+   |
+LL |     const ADD_REV: i32 =  T::ADD + (i32::MAX+1);
+   |                                    ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22
+   |
+LL |     const DIV: i32 = (1/0) + T::DIV;
+   |                      ^^^^^ attempt to divide `1_i32` by zero
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35
+   |
+LL |     const DIV_REV: i32 = T::DIV + (1/0);
+   |                                   ^^^^^ attempt to divide `1_i32` by zero
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22
+   |
+LL |     const OOB: i32 = [1][1] + T::OOB;
+   |                      ^^^^^^ index out of bounds: the length is 1 but the index is 1
+
+error: this operation will panic at runtime
+  --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35
+   |
+LL |     const OOB_REV: i32 = T::OOB + [1][1];
+   |                                   ^^^^^^ index out of bounds: the length is 1 but the index is 1
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.rs b/src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs
similarity index 100%
rename from src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.rs
rename to src/test/ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs
diff --git a/src/test/ui/associated-item/issue-48027.stderr b/src/test/ui/associated-item/issue-48027.stderr
index 98b545c..92d74e3 100644
--- a/src/test/ui/associated-item/issue-48027.stderr
+++ b/src/test/ui/associated-item/issue-48027.stderr
@@ -1,15 +1,17 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/issue-48027.rs:6:6
    |
+LL | impl dyn Bar {}
+   |      ^^^^^^^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `X` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-48027.rs:2:11
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     const X: usize;
-   |           - ...because it contains this associated `const`
-...
-LL | impl dyn Bar {}
-   |      ^^^^^^^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `X` to another trait
+   |           ^ ...because it contains this associated `const`
 
 error[E0283]: type annotations needed
   --> $DIR/issue-48027.rs:3:32
diff --git a/src/test/ui/associated-type-bounds/assoc-type-bound-through-where-clause.rs b/src/test/ui/associated-type-bounds/assoc-type-bound-through-where-clause.rs
new file mode 100644
index 0000000..49f1114
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/assoc-type-bound-through-where-clause.rs
@@ -0,0 +1,16 @@
+// Check that `where Self::Output: Copy` is turned into a bound on `Op::Output`.
+
+//check-pass
+
+trait Op
+where
+    Self::Output: Copy,
+{
+    type Output;
+}
+
+fn duplicate<T: Op>(x: T::Output) -> (T::Output, T::Output) {
+    (x, x)
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs
index 498a555..73b23da 100644
--- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs
+++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs
@@ -12,7 +12,9 @@
 
 fn main() {}
 
-trait Bar { type Assoc; }
+trait Bar {
+    type Assoc;
+}
 
 trait Thing {
     type Out;
@@ -20,11 +22,14 @@
 }
 
 struct AssocNoCopy;
-impl Bar for AssocNoCopy { type Assoc = String; }
+impl Bar for AssocNoCopy {
+    type Assoc = String;
+}
 
 impl Thing for AssocNoCopy {
     type Out = Box<dyn Bar<Assoc: Copy>>;
     //~^ ERROR the trait bound `String: Copy` is not satisfied
+    //~| ERROR the trait bound `String: Copy` is not satisfied
 
     fn func() -> Self::Out {
         Box::new(AssocNoCopy)
diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr
index 5236f0e..414d74d 100644
--- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr
+++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr
@@ -1,11 +1,15 @@
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:26:28
+  --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
    |
 LL |     type Out = Box<dyn Bar<Assoc: Copy>>;
    |                            ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
-   |
-   = note: the return type of a function must have a statically known size
 
-error: aborting due to previous error
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
+   |
+LL |     type Out = Box<dyn Bar<Assoc: Copy>>;
+   |                            ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
index 556d890..0c4907f 100644
--- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
@@ -1,45 +1,55 @@
 // NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
 // This should hopefully be fixed with Chalk.
+// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 
 use std::fmt::Debug;
 use std::iter::Once;
 
-trait Lam<Binder> { type App; }
+trait Lam<Binder> {
+    type App;
+}
 
 #[derive(Clone)]
 struct L1;
-impl<'a> Lam<&'a u8> for L1 { type App = u8; }
+impl<'a> Lam<&'a u8> for L1 {
+    type App = u8;
+}
 
 #[derive(Clone)]
 struct L2;
-impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; }
+impl<'a, 'b> Lam<&'a &'b u8> for L2 {
+    type App = u8;
+}
 
 trait Case1 {
-    type C: Clone + Iterator<Item:
-        Send + Iterator<Item:
-            for<'a> Lam<&'a u8, App:
-                Debug
-            >
-        > + Sync>;
+    type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
+    //~^ ERROR `<<Self as Case1>::C as Iterator>::Item` is not an iterator
+    //~| ERROR `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
+    //~| ERROR `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
 }
 
 pub struct S1;
 impl Case1 for S1 {
-//~^ ERROR `<L1 as Lam<&'a u8>>::App` doesn't implement `Debug` [E0277]
     type C = Once<Once<L1>>;
 }
 
 fn assume_case1<T: Case1>() {
-//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `Debug` [E0277]
-//~| ERROR `<<T as Case1>::C as Iterator>::Item` is not an iterator [E0277]
-//~| ERROR `<<T as Case1>::C as Iterator>::Item` cannot be sent between threads safely [E0277]
-//~| ERROR `<<T as Case1>::C as Iterator>::Item` cannot be shared between threads safely [E0277]
-    fn assert_a<_0, A>() where A: Iterator<Item = _0>, _0: Debug {}
+    fn assert_a<_0, A>()
+    where
+        A: Iterator<Item = _0>,
+        _0: Debug,
+    {
+    }
     assert_a::<_, T::A>();
 
-    fn assert_b<_0, B>() where B: Iterator<Item = _0>, _0: 'static {}
+    fn assert_b<_0, B>()
+    where
+        B: Iterator<Item = _0>,
+        _0: 'static,
+    {
+    }
     assert_b::<_, T::B>();
 
     fn assert_c<_0, _1, _2, C>()
@@ -48,7 +58,8 @@
         _2: Send + Iterator<Item = _1>,
         _1: for<'a> Lam<&'a u8, App = _0>,
         _0: Debug,
-    {}
+    {
+    }
     assert_c::<_, _, _, T::C>();
 }
 
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
index 49b5e7f..1c49358 100644
--- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
@@ -1,79 +1,49 @@
-error[E0277]: `<L1 as Lam<&'a u8>>::App` doesn't implement `Debug`
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:29:6
+error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:5
    |
-LL | trait Case1 {
-   |       ----- required by a bound in this
-...
-LL |                 Debug
-   |                 ----- required by this bound in `Case1`
-...
-LL | impl Case1 for S1 {
-   |      ^^^^^ `<L1 as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
    |
-   = help: the trait `for<'a> Debug` is not implemented for `<L1 as Lam<&'a u8>>::App`
-
-error[E0277]: `<<T as Case1>::C as Iterator>::Item` is not an iterator
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
-   |
-LL | fn assume_case1<T: Case1>() {
-   |                    ^^^^^ `<<T as Case1>::C as Iterator>::Item` is not an iterator
-   |
-   = help: the trait `Iterator` is not implemented for `<<T as Case1>::C as Iterator>::Item`
+   = help: the trait `Iterator` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
 help: consider further restricting the associated type
    |
-LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as Iterator>::Item: Iterator {
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: `<<T as Case1>::C as Iterator>::Item` cannot be sent between threads safely
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
+error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:36
    |
-LL | trait Case1 {
-   |       ----- required by a bound in this
-LL |     type C: Clone + Iterator<Item:
-LL |         Send + Iterator<Item:
-   |         ---- required by this bound in `Case1`
-...
-LL | fn assume_case1<T: Case1>() {
-   |                    ^^^^^ `<<T as Case1>::C as Iterator>::Item` cannot be sent between threads safely
+LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
+   |                                    ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
+   | 
+  ::: $SRC_DIR/core/src/marker.rs:LL:COL
    |
-   = help: the trait `Send` is not implemented for `<<T as Case1>::C as Iterator>::Item`
+LL | pub unsafe auto trait Send {
+   | -------------------------- required by this bound in `Send`
+   |
+   = help: the trait `Send` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
 help: consider further restricting the associated type
    |
-LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as Iterator>::Item: Send {
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Send {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: `<<T as Case1>::C as Iterator>::Item` cannot be shared between threads safely
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
+error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:93
    |
-LL | trait Case1 {
-   |       ----- required by a bound in this
-...
-LL |         > + Sync>;
-   |             ---- required by this bound in `Case1`
-...
-LL | fn assume_case1<T: Case1>() {
-   |                    ^^^^^ `<<T as Case1>::C as Iterator>::Item` cannot be shared between threads safely
+LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
+   |                                                                                             ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
+   | 
+  ::: $SRC_DIR/core/src/marker.rs:LL:COL
    |
-   = help: the trait `Sync` is not implemented for `<<T as Case1>::C as Iterator>::Item`
+LL | pub unsafe auto trait Sync {
+   | -------------------------- required by this bound in `Sync`
+   |
+   = help: the trait `Sync` is not implemented for `<<Self as Case1>::C as Iterator>::Item`
 help: consider further restricting the associated type
    |
-LL | fn assume_case1<T: Case1>() where <<T as Case1>::C as Iterator>::Item: Sync {
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Sync {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `Debug`
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20
-   |
-LL | trait Case1 {
-   |       ----- required by a bound in this
-...
-LL |                 Debug
-   |                 ----- required by this bound in `Case1`
-...
-LL | fn assume_case1<T: Case1>() {
-   |                    ^^^^^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = help: the trait `for<'a> Debug` is not implemented for `<_ as Lam<&'a u8>>::App`
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
index ceca54b..23be735 100644
--- a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
+++ b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(associated_type_bounds)]
 
 use std::fmt::Debug;
@@ -18,6 +16,7 @@
 
 trait Case1 {
     type A: Iterator<Item: Debug>;
+    //~^ ERROR `<<Self as Case1>::A as Iterator>::Item` doesn't implement `Debug`
 
     type B: Iterator<Item: 'static>;
 }
@@ -30,7 +29,11 @@
 
 // Ensure we don't have opaque `impl Trait` desugaring:
 
+// What is this supposed to mean? Rustc currently lowers `: Default` in the
+// bounds of `Out`, but trait selection can't find the bound since it applies
+// to a type other than `Self::Out`.
 pub trait Foo { type Out: Baz<Assoc: Default>; }
+//~^ ERROR trait bound `<<Self as Foo>::Out as Baz>::Assoc: Default` is not satisfied
 pub trait Baz { type Assoc; }
 
 #[derive(Default)]
diff --git a/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr
new file mode 100644
index 0000000..919b186
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr
@@ -0,0 +1,36 @@
+error[E0277]: `<<Self as Case1>::A as Iterator>::Item` doesn't implement `Debug`
+  --> $DIR/bounds-on-assoc-in-trait.rs:18:28
+   |
+LL |     type A: Iterator<Item: Debug>;
+   |                            ^^^^^ `<<Self as Case1>::A as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   | 
+  ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+   |
+LL | pub trait Debug {
+   | --------------- required by this bound in `Debug`
+   |
+   = help: the trait `Debug` is not implemented for `<<Self as Case1>::A as Iterator>::Item`
+help: consider further restricting the associated type
+   |
+LL | trait Case1 where <<Self as Case1>::A as Iterator>::Item: Debug {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `<<Self as Foo>::Out as Baz>::Assoc: Default` is not satisfied
+  --> $DIR/bounds-on-assoc-in-trait.rs:35:38
+   |
+LL | pub trait Foo { type Out: Baz<Assoc: Default>; }
+   |                                      ^^^^^^^ the trait `Default` is not implemented for `<<Self as Foo>::Out as Baz>::Assoc`
+   | 
+  ::: $SRC_DIR/core/src/default.rs:LL:COL
+   |
+LL | pub trait Default: Sized {
+   | ------------------------ required by this bound in `Default`
+   |
+help: consider further restricting the associated type
+   |
+LL | pub trait Foo where <<Self as Foo>::Out as Baz>::Assoc: Default { type Out: Baz<Assoc: Default>; }
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs
index 6c86053..39df9ba 100644
--- a/src/test/ui/associated-type-bounds/duplicate.rs
+++ b/src/test/ui/associated-type-bounds/duplicate.rs
@@ -60,11 +60,8 @@
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 
 fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
-//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
-//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
-//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
@@ -107,28 +104,16 @@
 
 type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
 type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
 type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
 type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
 type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
 type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
 
 trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
@@ -166,15 +151,9 @@
 
 type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
 type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
 type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
 //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-//~| ERROR could not find defining uses
-//~| ERROR could not find defining uses
 
 fn main() {}
diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr
index ac59e1f..de2876d 100644
--- a/src/test/ui/associated-type-bounds/duplicate.stderr
+++ b/src/test/ui/associated-type-bounds/duplicate.stderr
@@ -200,7 +200,7 @@
    |                               `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:68:40
+  --> $DIR/duplicate.rs:65:40
    |
 LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -208,7 +208,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:70:40
+  --> $DIR/duplicate.rs:67:40
    |
 LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -216,7 +216,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:72:43
+  --> $DIR/duplicate.rs:69:43
    |
 LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -224,7 +224,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:75:39
+  --> $DIR/duplicate.rs:72:39
    |
 LL | const CIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
    |                           ----------  ^^^^^^^^^^ re-bound here
@@ -232,7 +232,7 @@
    |                           `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:77:39
+  --> $DIR/duplicate.rs:74:39
    |
 LL | const CIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
    |                           ----------  ^^^^^^^^^^ re-bound here
@@ -240,7 +240,7 @@
    |                           `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:79:42
+  --> $DIR/duplicate.rs:76:42
    |
 LL | const CIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
    |                           -------------  ^^^^^^^^^^^^^ re-bound here
@@ -248,7 +248,7 @@
    |                           `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:81:40
+  --> $DIR/duplicate.rs:78:40
    |
 LL | static SIT1: impl Iterator<Item: Copy, Item: Send> = iter::empty();
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -256,7 +256,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:83:40
+  --> $DIR/duplicate.rs:80:40
    |
 LL | static SIT2: impl Iterator<Item: Copy, Item: Copy> = iter::empty();
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -264,7 +264,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:85:43
+  --> $DIR/duplicate.rs:82:43
    |
 LL | static SIT3: impl Iterator<Item: 'static, Item: 'static> = iter::empty();
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -272,7 +272,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:88:46
+  --> $DIR/duplicate.rs:85:46
    |
 LL | fn lit1() { let _: impl Iterator<Item: Copy, Item: Send> = iter::empty(); }
    |                                  ----------  ^^^^^^^^^^ re-bound here
@@ -280,7 +280,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:90:46
+  --> $DIR/duplicate.rs:87:46
    |
 LL | fn lit2() { let _: impl Iterator<Item: Copy, Item: Copy> = iter::empty(); }
    |                                  ----------  ^^^^^^^^^^ re-bound here
@@ -288,7 +288,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:92:49
+  --> $DIR/duplicate.rs:89:49
    |
 LL | fn lit3() { let _: impl Iterator<Item: 'static, Item: 'static> = iter::empty(); }
    |                                  -------------  ^^^^^^^^^^^^^ re-bound here
@@ -296,7 +296,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:95:35
+  --> $DIR/duplicate.rs:92:35
    |
 LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
    |                       ----------  ^^^^^^^^^^ re-bound here
@@ -304,7 +304,7 @@
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:97:35
+  --> $DIR/duplicate.rs:94:35
    |
 LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
    |                       ----------  ^^^^^^^^^^ re-bound here
@@ -312,7 +312,7 @@
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:99:38
+  --> $DIR/duplicate.rs:96:38
    |
 LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
    |                       -------------  ^^^^^^^^^^^^^ re-bound here
@@ -320,7 +320,7 @@
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:101:44
+  --> $DIR/duplicate.rs:98:44
    |
 LL | type TAW1<T> where T: Iterator<Item: Copy, Item: Send> = T;
    |                                ----------  ^^^^^^^^^^ re-bound here
@@ -328,7 +328,7 @@
    |                                `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:103:44
+  --> $DIR/duplicate.rs:100:44
    |
 LL | type TAW2<T> where T: Iterator<Item: Copy, Item: Copy> = T;
    |                                ----------  ^^^^^^^^^^ re-bound here
@@ -336,7 +336,7 @@
    |                                `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:105:47
+  --> $DIR/duplicate.rs:102:47
    |
 LL | type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
    |                                -------------  ^^^^^^^^^^^^^ re-bound here
@@ -344,7 +344,7 @@
    |                                `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:108:36
+  --> $DIR/duplicate.rs:105:36
    |
 LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -352,99 +352,39 @@
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:62:42
-   |
-LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> { iter::empty() }
-   |                              ----------  ^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:64:42
-   |
-LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> { iter::empty() }
-   |                              ----------  ^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:66:45
-   |
-LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> { iter::empty() }
-   |                              -------------  ^^^^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:108:51
-   |
-LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
-   |                                                   ^^^^^^^^^
-
-error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:111:36
+  --> $DIR/duplicate.rs:107:36
    |
 LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
    |                        ----------  ^^^^^^^^^^ re-bound here
    |                        |
    |                        `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:111:51
-   |
-LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
-   |                                                   ^^^^^^^^^
-
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:114:39
+  --> $DIR/duplicate.rs:109:39
    |
 LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
    |                        -------------  ^^^^^^^^^^^^^ re-bound here
    |                        |
    |                        `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:114:57
-   |
-LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
-   |                                                         ^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:117:14
-   |
-LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:117:40
+  --> $DIR/duplicate.rs:111:40
    |
 LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
    |                            ----------  ^^^^^^^^^^ re-bound here
    |                            |
    |                            `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:122:14
-   |
-LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:122:40
+  --> $DIR/duplicate.rs:113:40
    |
 LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
    |                            ----------  ^^^^^^^^^^ re-bound here
    |                            |
    |                            `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:127:14
-   |
-LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:127:43
+  --> $DIR/duplicate.rs:115:43
    |
 LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -452,7 +392,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:133:36
+  --> $DIR/duplicate.rs:118:36
    |
 LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -460,7 +400,7 @@
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:135:36
+  --> $DIR/duplicate.rs:120:36
    |
 LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -468,7 +408,7 @@
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:137:39
+  --> $DIR/duplicate.rs:122:39
    |
 LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
    |                        -------------  ^^^^^^^^^^^^^ re-bound here
@@ -476,7 +416,7 @@
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:139:34
+  --> $DIR/duplicate.rs:124:34
    |
 LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -484,7 +424,7 @@
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:141:34
+  --> $DIR/duplicate.rs:126:34
    |
 LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -492,7 +432,7 @@
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:143:37
+  --> $DIR/duplicate.rs:128:37
    |
 LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      -------------  ^^^^^^^^^^^^^ re-bound here
@@ -500,7 +440,7 @@
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:145:45
+  --> $DIR/duplicate.rs:130:45
    |
 LL | trait TRW1<T> where T: Iterator<Item: Copy, Item: Send> {}
    |                                 ----------  ^^^^^^^^^^ re-bound here
@@ -508,7 +448,7 @@
    |                                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:147:45
+  --> $DIR/duplicate.rs:132:45
    |
 LL | trait TRW2<T> where T: Iterator<Item: Copy, Item: Copy> {}
    |                                 ----------  ^^^^^^^^^^ re-bound here
@@ -516,7 +456,7 @@
    |                                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:149:48
+  --> $DIR/duplicate.rs:134:48
    |
 LL | trait TRW3<T> where T: Iterator<Item: 'static, Item: 'static> {}
    |                                 -------------  ^^^^^^^^^^^^^ re-bound here
@@ -524,7 +464,7 @@
    |                                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:151:46
+  --> $DIR/duplicate.rs:136:46
    |
 LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
    |                                  ----------  ^^^^^^^^^^ re-bound here
@@ -532,7 +472,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:151:46
+  --> $DIR/duplicate.rs:136:46
    |
 LL | trait TRSW1 where Self: Iterator<Item: Copy, Item: Send> {}
    |                                  ----------  ^^^^^^^^^^ re-bound here
@@ -540,7 +480,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:154:46
+  --> $DIR/duplicate.rs:139:46
    |
 LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
    |                                  ----------  ^^^^^^^^^^ re-bound here
@@ -548,7 +488,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:154:46
+  --> $DIR/duplicate.rs:139:46
    |
 LL | trait TRSW2 where Self: Iterator<Item: Copy, Item: Copy> {}
    |                                  ----------  ^^^^^^^^^^ re-bound here
@@ -556,7 +496,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:157:49
+  --> $DIR/duplicate.rs:142:49
    |
 LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
    |                                  -------------  ^^^^^^^^^^^^^ re-bound here
@@ -564,7 +504,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:157:49
+  --> $DIR/duplicate.rs:142:49
    |
 LL | trait TRSW3 where Self: Iterator<Item: 'static, Item: 'static> {}
    |                                  -------------  ^^^^^^^^^^^^^ re-bound here
@@ -572,31 +512,7 @@
    |                                  `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:160:43
-   |
-LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
-   |                               ----------  ^^^^^^^^^^ re-bound here
-   |                               |
-   |                               `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:162:43
-   |
-LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
-   |                               ----------  ^^^^^^^^^^ re-bound here
-   |                               |
-   |                               `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:164:46
-   |
-LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
-   |                               -------------  ^^^^^^^^^^^^^ re-bound here
-   |                               |
-   |                               `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:167:40
+  --> $DIR/duplicate.rs:152:40
    |
 LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -604,7 +520,7 @@
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:171:44
+  --> $DIR/duplicate.rs:154:44
    |
 LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
    |                                ----------  ^^^^^^^^^^ re-bound here
@@ -612,85 +528,37 @@
    |                                `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
-  --> $DIR/duplicate.rs:175:43
+  --> $DIR/duplicate.rs:156:43
    |
 LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
    |                            |
    |                            `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:117:28
+error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
+  --> $DIR/duplicate.rs:145:43
    |
-LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-   |                            ^^^^^^^^^^
+LL | trait TRA1 { type A: Iterator<Item: Copy, Item: Send>; }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:117:40
+error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
+  --> $DIR/duplicate.rs:147:43
    |
-LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-   |                                        ^^^^^^^^^^
+LL | trait TRA2 { type A: Iterator<Item: Copy, Item: Copy>; }
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:122:28
+error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
+  --> $DIR/duplicate.rs:149:46
    |
-LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-   |                            ^^^^^^^^^^
+LL | trait TRA3 { type A: Iterator<Item: 'static, Item: 'static>; }
+   |                               -------------  ^^^^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
 
-error: could not find defining uses
-  --> $DIR/duplicate.rs:122:40
-   |
-LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-   |                                        ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:127:28
-   |
-LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-   |                            ^^^^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:127:43
-   |
-LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-   |                                           ^^^^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:167:28
-   |
-LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
-   |                            ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:167:40
-   |
-LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
-   |                                        ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:171:32
-   |
-LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
-   |                                ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:171:44
-   |
-LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
-   |                                            ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:175:28
-   |
-LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
-   |                            ^^^^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/duplicate.rs:175:43
-   |
-LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
-   |                                           ^^^^^^^^^^^^^
-
-error: aborting due to 90 previous errors; 1 warning emitted
+error: aborting due to 69 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0719`.
diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs
index b74c038..5af0573 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.rs
+++ b/src/test/ui/associated-type-bounds/inside-adt.rs
@@ -3,32 +3,27 @@
 
 struct S1 { f: dyn Iterator<Item: Copy> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
 struct S2 { f: Box<dyn Iterator<Item: Copy>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
 struct S3 { f: dyn Iterator<Item: 'static> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
 
 enum E1 { V(dyn Iterator<Item: Copy>) }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
+//~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)`
 enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
 enum E3 { V(dyn Iterator<Item: 'static>) }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
+//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)`
 
 union U1 { f: dyn Iterator<Item: Copy> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
+//~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)`
 union U2 { f: Box<dyn Iterator<Item: Copy>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
 union U3 { f: dyn Iterator<Item: 'static> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-//~| ERROR could not find defining uses
+//~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)`
 
 fn main() {}
diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr
index a532bb0..74e858c 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.stderr
+++ b/src/test/ui/associated-type-bounds/inside-adt.stderr
@@ -5,106 +5,125 @@
    |                             ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:7:33
+  --> $DIR/inside-adt.rs:6:33
    |
 LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> }
    |                                 ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:10:29
+  --> $DIR/inside-adt.rs:8:29
    |
 LL | struct S3 { f: dyn Iterator<Item: 'static> }
    |                             ^^^^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:14:26
+  --> $DIR/inside-adt.rs:11:26
    |
 LL | enum E1 { V(dyn Iterator<Item: Copy>) }
    |                          ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:17:30
+  --> $DIR/inside-adt.rs:14:30
    |
 LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
    |                              ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:20:26
+  --> $DIR/inside-adt.rs:16:26
    |
 LL | enum E3 { V(dyn Iterator<Item: 'static>) }
    |                          ^^^^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:24:28
+  --> $DIR/inside-adt.rs:20:28
    |
 LL | union U1 { f: dyn Iterator<Item: Copy> }
    |                            ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:27:32
+  --> $DIR/inside-adt.rs:23:32
    |
 LL | union U2 { f: Box<dyn Iterator<Item: Copy>> }
    |                                ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:30:28
+  --> $DIR/inside-adt.rs:25:28
    |
 LL | union U3 { f: dyn Iterator<Item: 'static> }
    |                            ^^^^^^^^^^^^^
 
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:4:29
-   |
-LL | struct S1 { f: dyn Iterator<Item: Copy> }
-   |                             ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:7:33
-   |
-LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> }
-   |                                 ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:10:29
-   |
-LL | struct S3 { f: dyn Iterator<Item: 'static> }
-   |                             ^^^^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:14:26
+error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time
+  --> $DIR/inside-adt.rs:11:13
    |
 LL | enum E1 { V(dyn Iterator<Item: Copy>) }
-   |                          ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:17:30
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
-   |                              ^^^^^^^^^^
+   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL | enum E1 { V(&dyn Iterator<Item: Copy>) }
+   |             ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL | enum E1 { V(Box<dyn Iterator<Item: Copy>>) }
+   |             ^^^^                        ^
 
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:20:26
+error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time
+  --> $DIR/inside-adt.rs:16:13
    |
 LL | enum E3 { V(dyn Iterator<Item: 'static>) }
-   |                          ^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL | enum E3 { V(&dyn Iterator<Item: 'static>) }
+   |             ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL | enum E3 { V(Box<dyn Iterator<Item: 'static>>) }
+   |             ^^^^                           ^
 
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:24:28
+error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time
+  --> $DIR/inside-adt.rs:20:15
    |
 LL | union U1 { f: dyn Iterator<Item: Copy> }
-   |                            ^^^^^^^^^^
-
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:27:32
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-LL | union U2 { f: Box<dyn Iterator<Item: Copy>> }
-   |                                ^^^^^^^^^^
+   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)`
+   = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL | union U1 { f: &dyn Iterator<Item: Copy> }
+   |               ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL | union U1 { f: Box<dyn Iterator<Item: Copy>> }
+   |               ^^^^                        ^
 
-error: could not find defining uses
-  --> $DIR/inside-adt.rs:30:28
+error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time
+  --> $DIR/inside-adt.rs:25:15
    |
 LL | union U3 { f: dyn Iterator<Item: 'static> }
-   |                            ^^^^^^^^^^^^^
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)`
+   = note: no field of a union may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL | union U3 { f: &dyn Iterator<Item: 'static> }
+   |               ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL | union U3 { f: Box<dyn Iterator<Item: 'static>> }
+   |               ^^^^                           ^
 
-error: aborting due to 18 previous errors
+error: aborting due to 13 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-type-bounds/issue-70292.rs b/src/test/ui/associated-type-bounds/issue-70292.rs
new file mode 100644
index 0000000..945d768
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-70292.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+fn foo<F>(_: F)
+where
+    F: for<'a> Trait<Output: 'a>,
+{
+}
+
+trait Trait {
+    type Output;
+}
+
+impl<T> Trait for T {
+    type Output = ();
+}
+
+fn main() {
+    foo(());
+}
diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.rs b/src/test/ui/associated-type-bounds/issue-71443-1.rs
new file mode 100644
index 0000000..5d2a3e6
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-71443-1.rs
@@ -0,0 +1,9 @@
+#![feature(associated_type_bounds)]
+
+struct Incorrect;
+
+fn hello<F: for<'a> Iterator<Item: 'a>>() {
+    Incorrect //~ERROR: mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.stderr b/src/test/ui/associated-type-bounds/issue-71443-1.stderr
new file mode 100644
index 0000000..a9459ee
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-71443-1.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-71443-1.rs:6:5
+   |
+LL | fn hello<F: for<'a> Iterator<Item: 'a>>() {
+   |                                           - help: try adding a return type: `-> Incorrect`
+LL |     Incorrect
+   |     ^^^^^^^^^ expected `()`, found struct `Incorrect`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/associated-type-bounds/issue-71443-2.rs b/src/test/ui/associated-type-bounds/issue-71443-2.rs
new file mode 100644
index 0000000..813dcd6
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-71443-2.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+fn hello<'b, F>()
+where
+    for<'a> F: Iterator<Item: 'a> + 'b,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/trait-params.rs b/src/test/ui/associated-type-bounds/trait-params.rs
index b0703a4..a9aa274 100644
--- a/src/test/ui/associated-type-bounds/trait-params.rs
+++ b/src/test/ui/associated-type-bounds/trait-params.rs
@@ -1,4 +1,5 @@
 // build-pass (FIXME(62277): could be check-pass?)
+// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 
diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs
index 97c5acf..f1aab2a 100644
--- a/src/test/ui/associated-type-bounds/union-bounds.rs
+++ b/src/test/ui/associated-type-bounds/union-bounds.rs
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 #![feature(untagged_unions)]
diff --git a/src/test/ui/associated-types/associate-type-bound-normalization.rs b/src/test/ui/associated-types/associate-type-bound-normalization.rs
new file mode 100644
index 0000000..db09297
--- /dev/null
+++ b/src/test/ui/associated-types/associate-type-bound-normalization.rs
@@ -0,0 +1,25 @@
+// Make sure that we normalize bounds on associated types before checking them
+// as candidates.
+
+// check-pass
+
+trait Mul<T> {
+    type Output;
+}
+
+trait Matrix: Mul<<Self as Matrix>::Row, Output = ()> {
+    type Row;
+
+    type Transpose: Matrix<Row = Self::Row>;
+}
+
+fn is_mul<S, T: Mul<S, Output = ()>>() {}
+
+fn f<T: Matrix>() {
+    // The unnormalized bound on `T::Transpose` is
+    // `Mul<<T::Transpose as Matrix>::Row` which has to be normalized to be
+    // equal to `T::Row`.
+    is_mul::<T::Row, T::Transpose>();
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.rs b/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs
similarity index 100%
rename from src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.rs
rename to src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.rs
diff --git a/src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr b/src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr
similarity index 100%
rename from src/test/ui/associated-type/associated-type-projection-ambig-between-bound-and-where-clause.stderr
rename to src/test/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr
diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs b/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs
similarity index 100%
rename from src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.rs
rename to src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.rs
diff --git a/src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr b/src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr
similarity index 100%
rename from src/test/ui/associated-type/associated-type-projection-from-multiple-supertraits.stderr
rename to src/test/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr
diff --git a/src/test/ui/associated-type/associated-type-projection-from-supertrait.rs b/src/test/ui/associated-types/associated-type-projection-from-supertrait.rs
similarity index 100%
rename from src/test/ui/associated-type/associated-type-projection-from-supertrait.rs
rename to src/test/ui/associated-types/associated-type-projection-from-supertrait.rs
diff --git a/src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr b/src/test/ui/associated-types/associated-type-projection-from-supertrait.stderr
similarity index 100%
rename from src/test/ui/associated-type/associated-type-projection-from-supertrait.stderr
rename to src/test/ui/associated-types/associated-type-projection-from-supertrait.stderr
diff --git a/src/test/ui/associated-types/associated-types-bound-ambiguity.rs b/src/test/ui/associated-types/associated-types-bound-ambiguity.rs
new file mode 100644
index 0000000..9f179b6
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-bound-ambiguity.rs
@@ -0,0 +1,23 @@
+// Make sure that if there are multiple applicable bounds on a projection, we
+// consider them ambiguous. In this test we are initially trying to solve
+// `Self::Repr: From<_>`, which is ambiguous until we later infer `_` to
+// `{integer}`.
+
+// check-pass
+
+trait PrimeField: Sized {
+    type Repr: From<u64> + From<Self>;
+    type Repr2: From<Self> + From<u64>;
+
+    fn method() {
+        Self::Repr::from(10);
+        Self::Repr2::from(10);
+    }
+}
+
+fn function<T: PrimeField>() {
+    T::Repr::from(10);
+    T::Repr2::from(10);
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr
index b259941..0881258 100644
--- a/src/test/ui/associated-types/associated-types-path-2.stderr
+++ b/src/test/ui/associated-types/associated-types-path-2.stderr
@@ -47,7 +47,7 @@
    |            |
    |            expected due to this
    |
-help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     let _: i32 = f2(2i32).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/associated-types/associated-types-projection-bound-ambiguity.rs b/src/test/ui/associated-types/associated-types-projection-bound-ambiguity.rs
new file mode 100644
index 0000000..353f82e
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-projection-bound-ambiguity.rs
@@ -0,0 +1,16 @@
+// Check that if we have multiple applicable projection bounds we pick one (for
+// backwards compatibility reasons).
+
+// check-pass
+use std::ops::Mul;
+
+trait A {
+    type V;
+    type U: Mul<Self::V, Output = ()> + Mul<(), Output = ()>;
+}
+
+fn g<T: A<V = ()>>() {
+    let y: <T::U as Mul<()>>::Output = ();
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/associated-types-stream.rs b/src/test/ui/associated-types/associated-types-stream.rs
index 9695452..220ee6a 100644
--- a/src/test/ui/associated-types/associated-types-stream.rs
+++ b/src/test/ui/associated-types/associated-types-stream.rs
@@ -1,6 +1,7 @@
 // run-pass
 // Test references to the trait `Stream` in the bounds for associated
 // types defined on `Stream`. Issue #20551.
+// ignore-compare-mode-chalk
 
 
 trait Stream {
diff --git a/src/test/ui/associated-types/associated-types-unconstrained.stderr b/src/test/ui/associated-types/associated-types-unconstrained.stderr
index 2914a7f..9d084203 100644
--- a/src/test/ui/associated-types/associated-types-unconstrained.stderr
+++ b/src/test/ui/associated-types/associated-types-unconstrained.stderr
@@ -1,11 +1,14 @@
-error[E0284]: type annotations needed
+error[E0283]: type annotations needed
   --> $DIR/associated-types-unconstrained.rs:14:20
    |
+LL |     fn bar() -> isize;
+   |     ------------------ required by `Foo::bar`
+...
 LL |     let x: isize = Foo::bar();
    |                    ^^^^^^^^ cannot infer type
    |
-   = note: cannot satisfy `<_ as Foo>::A == _`
+   = note: cannot satisfy `_: Foo`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs
index fa75f6b..afb2b3d 100644
--- a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs
+++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs
@@ -6,11 +6,8 @@
     type B = Self::A;
 }
 
-// ...but is an error in any impl that doesn't override at least one of the defaults
 impl Tr for () {}
-//~^ ERROR overflow evaluating the requirement
 
-// As soon as at least one is redefined, it works:
 impl Tr for u8 {
     type A = u8;
 }
@@ -24,16 +21,14 @@
     type B = u8;
 }
 
-// ...but only if this actually breaks the cycle
+// ...but not in an impl that redefines one of the types.
 impl Tr for bool {
-    //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
     type A = Box<Self::B>;
     //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
 }
 // (the error is shown twice for some reason)
 
 impl Tr for usize {
-    //~^ ERROR type mismatch resolving `<usize as Tr>::B == _`
     type B = &'static Self::A;
     //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
 }
diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr
index 0aea30b..ae7150d 100644
--- a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr
+++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr
@@ -1,34 +1,15 @@
-error[E0275]: overflow evaluating the requirement `<() as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-1.rs:10:6
-   |
-LL | impl Tr for () {}
-   |      ^^
-
 error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-1.rs:28:6
-   |
-LL | impl Tr for bool {
-   |      ^^ cyclic type of infinite size
-
-error[E0271]: type mismatch resolving `<usize as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-1.rs:35:6
-   |
-LL | impl Tr for usize {
-   |      ^^ cyclic type of infinite size
-
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-1.rs:30:5
+  --> $DIR/defaults-cyclic-fail-1.rs:26:5
    |
 LL |     type A = Box<Self::B>;
    |     ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
 
 error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
-  --> $DIR/defaults-cyclic-fail-1.rs:37:5
+  --> $DIR/defaults-cyclic-fail-1.rs:32:5
    |
 LL |     type B = &'static Self::A;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0271, E0275.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs
index edcd310..ba4bb0d 100644
--- a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs
+++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs
@@ -8,11 +8,8 @@
     type B = Box<Self::A>;
 }
 
-// ...but is an error in any impl that doesn't override at least one of the defaults
 impl Tr for () {}
-//~^ ERROR type mismatch resolving `<() as Tr>::B == _`
 
-// As soon as at least one is redefined, it works:
 impl Tr for u8 {
     type A = u8;
 }
@@ -26,16 +23,13 @@
     type B = u8;
 }
 
-// ...but only if this actually breaks the cycle
 impl Tr for bool {
-    //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
     type A = Box<Self::B>;
     //~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
 }
 // (the error is shown twice for some reason)
 
 impl Tr for usize {
-    //~^ ERROR type mismatch resolving `<usize as Tr>::B == _`
     type B = &'static Self::A;
     //~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
 }
diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr
index f39021c..0dfbac2 100644
--- a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr
+++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr
@@ -1,33 +1,15 @@
-error[E0271]: type mismatch resolving `<() as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-2.rs:12:6
-   |
-LL | impl Tr for () {}
-   |      ^^ cyclic type of infinite size
-
 error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-2.rs:30:6
-   |
-LL | impl Tr for bool {
-   |      ^^ cyclic type of infinite size
-
-error[E0271]: type mismatch resolving `<usize as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-2.rs:37:6
-   |
-LL | impl Tr for usize {
-   |      ^^ cyclic type of infinite size
-
-error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
-  --> $DIR/defaults-cyclic-fail-2.rs:32:5
+  --> $DIR/defaults-cyclic-fail-2.rs:27:5
    |
 LL |     type A = Box<Self::B>;
    |     ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
 
 error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
-  --> $DIR/defaults-cyclic-fail-2.rs:39:5
+  --> $DIR/defaults-cyclic-fail-2.rs:33:5
    |
 LL |     type B = &'static Self::A;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr
index 09a8c8f..920f832 100644
--- a/src/test/ui/associated-types/defaults-specialization.stderr
+++ b/src/test/ui/associated-types/defaults-specialization.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0053]: method `make` has an incompatible type for trait
   --> $DIR/defaults-specialization.rs:19:18
diff --git a/src/test/ui/associated-types/defaults-suitability.rs b/src/test/ui/associated-types/defaults-suitability.rs
index 30c2555..504c957 100644
--- a/src/test/ui/associated-types/defaults-suitability.rs
+++ b/src/test/ui/associated-types/defaults-suitability.rs
@@ -1,10 +1,8 @@
 //! Checks that associated type defaults are properly validated.
 //!
 //! This means:
-//! * Default types are wfchecked
 //! * Default types are checked against where clauses on the assoc. type
-//!   (eg. `type Assoc: Clone = NotClone`), and also against where clauses on
-//!   the trait itself when possible
+//!   (eg. `type Assoc: Clone = NotClone`)
 
 #![feature(associated_type_defaults)]
 
@@ -17,15 +15,12 @@
 }
 
 // Where-clauses defined on the trait must also be considered
-trait Tr2 where Self::Ty: Clone {
-    //~^ ERROR the trait bound `NotClone: Clone` is not satisfied
+trait Tr2
+where
+    Self::Ty: Clone,
+{
     type Ty = NotClone;
-}
-
-// Independent of where-clauses (there are none here), default types must always be wf
-trait Tr3 {
-    type Ty = Vec<[u8]>;
-    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    //~^ ERROR the trait bound `NotClone: Clone` is not satisfied
 }
 
 // Involved type parameters must fulfill all bounds required by defaults that mention them
@@ -43,7 +38,7 @@
 trait IsU8<T> {}
 impl<T> IsU8<u8> for T {}
 
-// Test that mentioning the assoc. type inside where clauses works
+// Test that mentioning the assoc. type inside where clauses is not allowed
 trait C where
     Vec<Self::Assoc>: Clone,
     Self::Assoc: IsU8<Self::Assoc>,
@@ -55,13 +50,11 @@
 // Test that we get all expected errors if that default is unsuitable
 trait D where
     Vec<Self::Assoc>: Clone,
-    //~^ ERROR the trait bound `NotClone: Clone` is not satisfied
     Self::Assoc: IsU8<Self::Assoc>,
-    //~^ ERROR the trait bound `NotClone: IsU8<NotClone>` is not satisfied
     bool: IsU8<Self::Assoc>,
-    //~^ ERROR the trait bound `bool: IsU8<NotClone>` is not satisfied
 {
     type Assoc = NotClone;
+    //~^ ERROR the trait bound `NotClone: IsU8<NotClone>` is not satisfied
 }
 
 // Test behavior of the check when defaults refer to other defaults:
@@ -85,18 +78,20 @@
 
 // Adding the `Baz: Clone` bound isn't enough since the default is type
 // parameter `T`, which also might not be `Clone`.
-trait Foo3<T> where
+trait Foo3<T>
+where
     Self::Bar: Clone,
     Self::Baz: Clone,
-    //~^ ERROR the trait bound `T: Clone` is not satisfied
 {
     type Bar = Vec<Self::Baz>;
     type Baz = T;
+    //~^ ERROR the trait bound `T: Clone` is not satisfied
 }
 
 // This one finally works, with `Clone` bounds on all assoc. types and the type
 // parameter.
-trait Foo4<T> where
+trait Foo4<T>
+where
     T: Clone,
 {
     type Bar: Clone = Vec<Self::Baz>;
diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr
index c2ad4c5..274d09f 100644
--- a/src/test/ui/associated-types/defaults-suitability.stderr
+++ b/src/test/ui/associated-types/defaults-suitability.stderr
@@ -1,27 +1,32 @@
 error[E0277]: the trait bound `NotClone: Clone` is not satisfied
-  --> $DIR/defaults-suitability.rs:15:14
+  --> $DIR/defaults-suitability.rs:13:5
    |
-LL | trait Tr {
-   | -------- required by `Tr`
 LL |     type Ty: Clone = NotClone;
-   |              ^^^^^ the trait `Clone` is not implemented for `NotClone`
+   |     ^^^^^^^^^-----^^^^^^^^^^^^
+   |     |        |
+   |     |        required by this bound in `Tr::Ty`
+   |     the trait `Clone` is not implemented for `NotClone`
 
 error[E0277]: the trait bound `NotClone: Clone` is not satisfied
-  --> $DIR/defaults-suitability.rs:20:27
+  --> $DIR/defaults-suitability.rs:22:5
    |
-LL | trait Tr2 where Self::Ty: Clone {
-   | --------------------------^^^^^
-   | |                         |
-   | |                         the trait `Clone` is not implemented for `NotClone`
-   | required by `Tr2`
+LL |     Self::Ty: Clone,
+   |               ----- required by this bound in `Tr2::Ty`
+LL | {
+LL |     type Ty = NotClone;
+   |     ^^^^^--^^^^^^^^^^^^
+   |     |    |
+   |     |    required by a bound in this
+   |     the trait `Clone` is not implemented for `NotClone`
 
 error[E0277]: the trait bound `T: Clone` is not satisfied
-  --> $DIR/defaults-suitability.rs:33:15
+  --> $DIR/defaults-suitability.rs:28:5
    |
-LL | trait Foo<T> {
-   | ------------ required by `Foo`
 LL |     type Bar: Clone = Vec<T>;
-   |               ^^^^^ the trait `Clone` is not implemented for `T`
+   |     ^^^^^^^^^^-----^^^^^^^^^^
+   |     |         |
+   |     |         required by this bound in `Foo::Bar`
+   |     the trait `Clone` is not implemented for `T`
    |
    = note: required because of the requirements on the impl of `Clone` for `Vec<T>`
 help: consider restricting type parameter `T`
@@ -30,64 +35,34 @@
    |            ^^^^^^^
 
 error[E0277]: the trait bound `(): Foo<Self>` is not satisfied
-  --> $DIR/defaults-suitability.rs:39:17
+  --> $DIR/defaults-suitability.rs:34:5
    |
-LL | trait Bar: Sized {
-   | ---------------- required by `Bar`
-LL |     // `(): Foo<Self>` might hold for some possible impls but not all.
 LL |     type Assoc: Foo<Self> = ();
-   |                 ^^^^^^^^^ the trait `Foo<Self>` is not implemented for `()`
+   |     ^^^^^^^^^^^^---------^^^^^^
+   |     |           |
+   |     |           required by this bound in `Bar::Assoc`
+   |     the trait `Foo<Self>` is not implemented for `()`
 
 error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied
-  --> $DIR/defaults-suitability.rs:59:18
+  --> $DIR/defaults-suitability.rs:56:5
    |
-LL | / trait D where
-LL | |     Vec<Self::Assoc>: Clone,
-LL | |
-LL | |     Self::Assoc: IsU8<Self::Assoc>,
-   | |                  ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
-...  |
-LL | |     type Assoc = NotClone;
-LL | | }
-   | |_- required by `D`
-
-error[E0277]: the trait bound `bool: IsU8<NotClone>` is not satisfied
-  --> $DIR/defaults-suitability.rs:61:11
-   |
-LL | / trait D where
-LL | |     Vec<Self::Assoc>: Clone,
-LL | |
-LL | |     Self::Assoc: IsU8<Self::Assoc>,
-LL | |
-LL | |     bool: IsU8<Self::Assoc>,
-   | |           ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `bool`
-...  |
-LL | |     type Assoc = NotClone;
-LL | | }
-   | |_- required by `D`
-
-error[E0277]: the trait bound `NotClone: Clone` is not satisfied
-  --> $DIR/defaults-suitability.rs:57:23
-   |
-LL | / trait D where
-LL | |     Vec<Self::Assoc>: Clone,
-   | |                       ^^^^^ the trait `Clone` is not implemented for `NotClone`
-LL | |
-LL | |     Self::Assoc: IsU8<Self::Assoc>,
-...  |
-LL | |     type Assoc = NotClone;
-LL | | }
-   | |_- required by `D`
-   |
-   = note: required because of the requirements on the impl of `Clone` for `Vec<NotClone>`
+LL |     Self::Assoc: IsU8<Self::Assoc>,
+   |                  ----------------- required by this bound in `D::Assoc`
+...
+LL |     type Assoc = NotClone;
+   |     ^^^^^-----^^^^^^^^^^^^
+   |     |    |
+   |     |    required by a bound in this
+   |     the trait `IsU8<NotClone>` is not implemented for `NotClone`
 
 error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: Clone` is not satisfied
-  --> $DIR/defaults-suitability.rs:72:15
+  --> $DIR/defaults-suitability.rs:65:5
    |
-LL | trait Foo2<T> {
-   | ------------- required by `Foo2`
 LL |     type Bar: Clone = Vec<Self::Baz>;
-   |               ^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
+   |     ^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^
+   |     |         |
+   |     |         required by this bound in `Foo2::Bar`
+   |     the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
    |
    = note: required because of the requirements on the impl of `Clone` for `Vec<<Self as Foo2<T>>::Baz>`
 help: consider further restricting the associated type
@@ -96,12 +71,13 @@
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: Clone` is not satisfied
-  --> $DIR/defaults-suitability.rs:81:15
+  --> $DIR/defaults-suitability.rs:74:5
    |
-LL | trait Foo25<T: Clone> {
-   | --------------------- required by `Foo25`
 LL |     type Bar: Clone = Vec<Self::Baz>;
-   |               ^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
+   |     ^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^
+   |     |         |
+   |     |         required by this bound in `Foo25::Bar`
+   |     the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
    |
    = note: required because of the requirements on the impl of `Clone` for `Vec<<Self as Foo25<T>>::Baz>`
 help: consider further restricting the associated type
@@ -110,36 +86,22 @@
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `T: Clone` is not satisfied
-  --> $DIR/defaults-suitability.rs:90:16
+  --> $DIR/defaults-suitability.rs:87:5
    |
-LL | / trait Foo3<T> where
-LL | |     Self::Bar: Clone,
-LL | |     Self::Baz: Clone,
-   | |                ^^^^^ the trait `Clone` is not implemented for `T`
-LL | |
-...  |
-LL | |     type Baz = T;
-LL | | }
-   | |_- required by `Foo3`
+LL |     Self::Baz: Clone,
+   |                ----- required by this bound in `Foo3::Baz`
+...
+LL |     type Baz = T;
+   |     ^^^^^---^^^^^
+   |     |    |
+   |     |    required by a bound in this
+   |     the trait `Clone` is not implemented for `T`
    |
 help: consider further restricting type parameter `T`
    |
 LL |     Self::Baz: Clone, T: Clone
    |                     ^^^^^^^^^^
 
-error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/defaults-suitability.rs:27:5
-   |
-LL |     type Ty = Vec<[u8]>;
-   |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   | 
-  ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
-   |
-LL | pub struct Vec<T> {
-   |                - required by this bound in `Vec`
-   |
-   = help: the trait `Sized` is not implemented for `[u8]`
-
-error: aborting due to 11 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.rs b/src/test/ui/associated-types/defaults-unsound-62211-1.rs
index f283d22..fa6a208 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-1.rs
+++ b/src/test/ui/associated-types/defaults-unsound-62211-1.rs
@@ -11,22 +11,17 @@
 
 use std::{
     fmt::Display,
-    ops::{AddAssign, Deref}
+    ops::{AddAssign, Deref},
 };
 
-
 trait UncheckedCopy: Sized {
     // This Output is said to be Copy. Yet we default to Self
     // and it's accepted, not knowing if Self ineed is Copy
-    type Output: Copy
+    type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
     //~^ ERROR the trait bound `Self: Copy` is not satisfied
-    + Deref<Target = str>
-    //~^ ERROR the trait bound `Self: Deref` is not satisfied
-    + AddAssign<&'static str>
-    //~^ ERROR cannot add-assign `&'static str` to `Self`
-    + From<Self>
-    + Display = Self;
-    //~^ ERROR `Self` doesn't implement `std::fmt::Display`
+    //~| ERROR the trait bound `Self: Deref` is not satisfied
+    //~| ERROR cannot add-assign `&'static str` to `Self`
+    //~| ERROR `Self` doesn't implement `std::fmt::Display`
 
     // We said the Output type was Copy, so we can Copy it freely!
     fn unchecked_copy(other: &Self::Output) -> Self::Output {
@@ -39,10 +34,6 @@
 }
 
 impl<T> UncheckedCopy for T {}
-//~^ ERROR `T` doesn't implement `std::fmt::Display`
-//~| ERROR the trait bound `T: Deref` is not satisfied
-//~| ERROR cannot add-assign `&'static str` to `T`
-//~| ERROR the trait bound `T: Copy` is not satisfied
 
 fn bug<T: UncheckedCopy>(origin: T) {
     let origin = T::make_origin(origin);
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
index 29a7c2e..8e446cf 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
@@ -1,53 +1,11 @@
-error[E0277]: the trait bound `Self: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:21:18
-   |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     type Output: Copy
-   |                  ^^^^ the trait `Copy` is not implemented for `Self`
-   |
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Copy {
-   |                            ^^^^^^
-
-error[E0277]: cannot add-assign `&'static str` to `Self`
-  --> $DIR/defaults-unsound-62211-1.rs:25:7
-   |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     + AddAssign<&'static str>
-   |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
-   |
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `Self: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:23:7
-   |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     + Deref<Target = str>
-   |       ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self`
-   |
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Deref {
-   |                            ^^^^^^^
-
 error[E0277]: `Self` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-1.rs:28:7
+  --> $DIR/defaults-unsound-62211-1.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     + Display = Self;
-   |       ^^^^^^^ `Self` cannot be formatted with the default formatter
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^^
+   |     |                                                                                |
+   |     |                                                                                required by this bound in `UncheckedCopy::Output`
+   |     `Self` cannot be formatted with the default formatter
    |
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider further restricting `Self`
@@ -55,75 +13,48 @@
 LL | trait UncheckedCopy: Sized + std::fmt::Display {
    |                            ^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: `T` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-1.rs:41:9
+error[E0277]: the trait bound `Self: Deref` is not satisfied
+  --> $DIR/defaults-unsound-62211-1.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     + Display = Self;
-   |       ------- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |                   |
+   |     |                   required by this bound in `UncheckedCopy::Output`
+   |     the trait `Deref` is not implemented for `Self`
    |
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-help: consider restricting type parameter `T`
+help: consider further restricting `Self`
    |
-LL | impl<T: std::fmt::Display> UncheckedCopy for T {}
-   |       ^^^^^^^^^^^^^^^^^^^
+LL | trait UncheckedCopy: Sized + Deref {
+   |                            ^^^^^^^
 
-error[E0277]: the trait bound `T: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:41:9
+error[E0277]: cannot add-assign `&'static str` to `Self`
+  --> $DIR/defaults-unsound-62211-1.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     + Deref<Target = str>
-   |       ------------------- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T`
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |                                         |
+   |     |                                         required by this bound in `UncheckedCopy::Output`
+   |     no implementation for `Self += &'static str`
    |
-help: consider restricting type parameter `T`
+help: consider further restricting `Self`
    |
-LL | impl<T: Deref> UncheckedCopy for T {}
-   |       ^^^^^^^
+LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: cannot add-assign `&'static str` to `T`
-  --> $DIR/defaults-unsound-62211-1.rs:41:9
+error[E0277]: the trait bound `Self: Copy` is not satisfied
+  --> $DIR/defaults-unsound-62211-1.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     + AddAssign<&'static str>
-   |       ----------------------- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ no implementation for `T += &'static str`
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |            |
+   |     |            required by this bound in `UncheckedCopy::Output`
+   |     the trait `Copy` is not implemented for `Self`
    |
-help: consider restricting type parameter `T`
+help: consider further restricting `Self`
    |
-LL | impl<T: AddAssign<&'static str>> UncheckedCopy for T {}
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait UncheckedCopy: Sized + Copy {
+   |                            ^^^^^^
 
-error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-1.rs:41:9
-   |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     type Output: Copy
-   |                  ---- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | impl<T: Copy> UncheckedCopy for T {}
-   |       ^^^^^^
-
-error: aborting due to 8 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.rs b/src/test/ui/associated-types/defaults-unsound-62211-2.rs
index 5518cda..c13ec77 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-2.rs
+++ b/src/test/ui/associated-types/defaults-unsound-62211-2.rs
@@ -11,22 +11,17 @@
 
 use std::{
     fmt::Display,
-    ops::{AddAssign, Deref}
+    ops::{AddAssign, Deref},
 };
 
-
 trait UncheckedCopy: Sized {
     // This Output is said to be Copy. Yet we default to Self
     // and it's accepted, not knowing if Self ineed is Copy
-    type Output: Copy
+    type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
     //~^ ERROR the trait bound `Self: Copy` is not satisfied
-    + Deref<Target = str>
-    //~^ ERROR the trait bound `Self: Deref` is not satisfied
-    + AddAssign<&'static str>
-    //~^ ERROR cannot add-assign `&'static str` to `Self`
-    + From<Self>
-    + Display = Self;
-    //~^ ERROR `Self` doesn't implement `std::fmt::Display`
+    //~| ERROR the trait bound `Self: Deref` is not satisfied
+    //~| ERROR cannot add-assign `&'static str` to `Self`
+    //~| ERROR `Self` doesn't implement `std::fmt::Display`
 
     // We said the Output type was Copy, so we can Copy it freely!
     fn unchecked_copy(other: &Self::Output) -> Self::Output {
@@ -39,10 +34,6 @@
 }
 
 impl<T> UncheckedCopy for T {}
-//~^ ERROR `T` doesn't implement `std::fmt::Display`
-//~| ERROR the trait bound `T: Deref` is not satisfied
-//~| ERROR cannot add-assign `&'static str` to `T`
-//~| ERROR the trait bound `T: Copy` is not satisfied
 
 fn bug<T: UncheckedCopy>(origin: T) {
     let origin = T::make_origin(origin);
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
index 49c6609..93f4f49 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
@@ -1,53 +1,11 @@
-error[E0277]: the trait bound `Self: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:21:18
-   |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     type Output: Copy
-   |                  ^^^^ the trait `Copy` is not implemented for `Self`
-   |
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Copy {
-   |                            ^^^^^^
-
-error[E0277]: cannot add-assign `&'static str` to `Self`
-  --> $DIR/defaults-unsound-62211-2.rs:25:7
-   |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     + AddAssign<&'static str>
-   |       ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
-   |
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `Self: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:23:7
-   |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     + Deref<Target = str>
-   |       ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self`
-   |
-help: consider further restricting `Self`
-   |
-LL | trait UncheckedCopy: Sized + Deref {
-   |                            ^^^^^^^
-
 error[E0277]: `Self` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-2.rs:28:7
+  --> $DIR/defaults-unsound-62211-2.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   | -------------------------- required by `UncheckedCopy`
-...
-LL |     + Display = Self;
-   |       ^^^^^^^ `Self` cannot be formatted with the default formatter
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^^
+   |     |                                                                                |
+   |     |                                                                                required by this bound in `UncheckedCopy::Output`
+   |     `Self` cannot be formatted with the default formatter
    |
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
 help: consider further restricting `Self`
@@ -55,75 +13,48 @@
 LL | trait UncheckedCopy: Sized + std::fmt::Display {
    |                            ^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: `T` doesn't implement `std::fmt::Display`
-  --> $DIR/defaults-unsound-62211-2.rs:41:9
+error[E0277]: the trait bound `Self: Deref` is not satisfied
+  --> $DIR/defaults-unsound-62211-2.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     + Display = Self;
-   |       ------- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^-------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |                   |
+   |     |                   required by this bound in `UncheckedCopy::Output`
+   |     the trait `Deref` is not implemented for `Self`
    |
-   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
-help: consider restricting type parameter `T`
+help: consider further restricting `Self`
    |
-LL | impl<T: std::fmt::Display> UncheckedCopy for T {}
-   |       ^^^^^^^^^^^^^^^^^^^
+LL | trait UncheckedCopy: Sized + Deref {
+   |                            ^^^^^^^
 
-error[E0277]: the trait bound `T: Deref` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:41:9
+error[E0277]: cannot add-assign `&'static str` to `Self`
+  --> $DIR/defaults-unsound-62211-2.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     + Deref<Target = str>
-   |       ------------------- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T`
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |                                         |
+   |     |                                         required by this bound in `UncheckedCopy::Output`
+   |     no implementation for `Self += &'static str`
    |
-help: consider restricting type parameter `T`
+help: consider further restricting `Self`
    |
-LL | impl<T: Deref> UncheckedCopy for T {}
-   |       ^^^^^^^
+LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0277]: cannot add-assign `&'static str` to `T`
-  --> $DIR/defaults-unsound-62211-2.rs:41:9
+error[E0277]: the trait bound `Self: Copy` is not satisfied
+  --> $DIR/defaults-unsound-62211-2.rs:20:5
    |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     + AddAssign<&'static str>
-   |       ----------------------- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ no implementation for `T += &'static str`
+LL |     type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
+   |     ^^^^^^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |            |
+   |     |            required by this bound in `UncheckedCopy::Output`
+   |     the trait `Copy` is not implemented for `Self`
    |
-help: consider restricting type parameter `T`
+help: consider further restricting `Self`
    |
-LL | impl<T: AddAssign<&'static str>> UncheckedCopy for T {}
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait UncheckedCopy: Sized + Copy {
+   |                            ^^^^^^
 
-error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/defaults-unsound-62211-2.rs:41:9
-   |
-LL | trait UncheckedCopy: Sized {
-   |       ------------- required by a bound in this
-...
-LL |     type Output: Copy
-   |                  ---- required by this bound in `UncheckedCopy`
-...
-LL | impl<T> UncheckedCopy for T {}
-   |         ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | impl<T: Copy> UncheckedCopy for T {}
-   |       ^^^^^^
-
-error: aborting due to 8 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/defaults-wf.rs b/src/test/ui/associated-types/defaults-wf.rs
new file mode 100644
index 0000000..99b5125
--- /dev/null
+++ b/src/test/ui/associated-types/defaults-wf.rs
@@ -0,0 +1,11 @@
+// Check that associated type defaults are wf checked.
+
+#![feature(associated_type_defaults)]
+
+// Default types must always be wf
+trait Tr3 {
+    type Ty = Vec<[u8]>;
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/defaults-wf.stderr b/src/test/ui/associated-types/defaults-wf.stderr
new file mode 100644
index 0000000..f9044c2
--- /dev/null
+++ b/src/test/ui/associated-types/defaults-wf.stderr
@@ -0,0 +1,16 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/defaults-wf.rs:7:5
+   |
+LL |     type Ty = Vec<[u8]>;
+   |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   | 
+  ::: $SRC_DIR/alloc/src/vec.rs:LL:COL
+   |
+LL | pub struct Vec<T> {
+   |                - required by this bound in `Vec`
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
index 5db619d..a04144b 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
@@ -1,3 +1,4 @@
+// ignore-compare-mode-chalk
 trait Z<'a, T: ?Sized>
 where
     T: Z<'a, u16>,
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
index 9a70194..b48ff97 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+  --> $DIR/hr-associated-type-bound-param-2.rs:4:8
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
@@ -15,7 +15,7 @@
              <&mut T as Clone>
 
 error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:15:14
+  --> $DIR/hr-associated-type-bound-param-2.rs:16:14
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
@@ -31,7 +31,7 @@
              <&mut T as Clone>
 
 error[E0277]: the trait bound `for<'b> <u16 as Z<'b, u16>>::W: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
+  --> $DIR/hr-associated-type-bound-param-2.rs:4:8
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
index ec627c7..fc3a851 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
@@ -1,3 +1,4 @@
+// ignore-compare-mode-chalk
 trait Cycle: Sized {
     type Next: Cycle<Next = Self>;
 }
diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
index 81eceb4..df25f7a 100644
--- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
+++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `for<'b> <Box<T> as X<'b, Box<T>>>::U: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:26:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:27:14
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
@@ -15,7 +15,7 @@
              <&mut T as Clone>
 
 error[E0277]: the trait bound `for<'b> <Vec<T> as X<'b, Vec<T>>>::U: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:26:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:27:14
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
@@ -31,7 +31,7 @@
              <&mut T as Clone>
 
 error[E0277]: the trait bound `for<'b> <Vec<T> as X<'b, Vec<T>>>::U: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:32:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:33:14
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
@@ -47,7 +47,7 @@
              <&mut T as Clone>
 
 error[E0277]: the trait bound `for<'b> <Box<T> as X<'b, Box<T>>>::U: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:32:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:33:14
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
index 566e390..b0e9e33 100644
--- a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
+++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr
@@ -9,7 +9,6 @@
    |
    = note: expected associated type `<impl Bar as Foo>::Item`
                          found type `i32`
-   = note: the return type of a function must have a statically known size
 help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
    |
 LL | fn bar() -> impl Bar<Item = i32> {
diff --git a/src/test/ui/associated-types/issue-43924.rs b/src/test/ui/associated-types/issue-43924.rs
index 26f1183..6a63b3e 100644
--- a/src/test/ui/associated-types/issue-43924.rs
+++ b/src/test/ui/associated-types/issue-43924.rs
@@ -4,12 +4,13 @@
 // type-checked.
 
 trait Foo<T: Default + ToString> {
-    type Out: Default + ToString + ?Sized = dyn ToString;  //~ error: not satisfied
+    type Out: Default + ToString + ?Sized = dyn ToString;  //~ ERROR not satisfied
 }
 
-impl Foo<u32> for () {}  //~ error: not satisfied
-impl Foo<u64> for () {}  //~ error: not satisfied
+impl Foo<u32> for () {}
+impl Foo<u64> for () {}
 
 fn main() {
     assert_eq!(<() as Foo<u32>>::Out::default().to_string(), "false");
+    //~^ ERROR no function or associated item named `default` found for trait object
 }
diff --git a/src/test/ui/associated-types/issue-43924.stderr b/src/test/ui/associated-types/issue-43924.stderr
index 661730b..8d4ecac 100644
--- a/src/test/ui/associated-types/issue-43924.stderr
+++ b/src/test/ui/associated-types/issue-43924.stderr
@@ -1,33 +1,19 @@
 error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied
-  --> $DIR/issue-43924.rs:7:15
+  --> $DIR/issue-43924.rs:7:5
    |
-LL | trait Foo<T: Default + ToString> {
-   | -------------------------------- required by `Foo`
 LL |     type Out: Default + ToString + ?Sized = dyn ToString;
-   |               ^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
+   |     ^^^^^^^^^^-------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |         |
+   |     |         required by this bound in `Foo::Out`
+   |     the trait `Default` is not implemented for `(dyn ToString + 'static)`
 
-error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied
-  --> $DIR/issue-43924.rs:10:6
+error[E0599]: no function or associated item named `default` found for trait object `(dyn ToString + 'static)` in the current scope
+  --> $DIR/issue-43924.rs:14:39
    |
-LL | trait Foo<T: Default + ToString> {
-   |       --- required by a bound in this
-LL |     type Out: Default + ToString + ?Sized = dyn ToString;
-   |               ------- required by this bound in `Foo`
-...
-LL | impl Foo<u32> for () {}
-   |      ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
+LL |     assert_eq!(<() as Foo<u32>>::Out::default().to_string(), "false");
+   |                                       ^^^^^^^ function or associated item not found in `(dyn ToString + 'static)`
 
-error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied
-  --> $DIR/issue-43924.rs:11:6
-   |
-LL | trait Foo<T: Default + ToString> {
-   |       --- required by a bound in this
-LL |     type Out: Default + ToString + ?Sized = dyn ToString;
-   |               ------- required by this bound in `Foo`
-...
-LL | impl Foo<u64> for () {}
-   |      ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
+error: aborting due to 2 previous errors
 
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/issue-54108.rs b/src/test/ui/associated-types/issue-54108.rs
new file mode 100644
index 0000000..87f67ce
--- /dev/null
+++ b/src/test/ui/associated-types/issue-54108.rs
@@ -0,0 +1,41 @@
+use std::ops::Add;
+
+pub trait Encoder {
+    type Size: Add<Output = Self::Size>;
+
+    fn foo(&self) -> Self::Size;
+}
+
+pub trait SubEncoder: Encoder {
+    type ActualSize;
+
+    fn bar(&self) -> Self::Size;
+}
+
+impl<T> Encoder for T
+where
+    T: SubEncoder,
+{
+    type Size = <Self as SubEncoder>::ActualSize;
+    //~^ ERROR: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize`
+
+    fn foo(&self) -> Self::Size {
+        self.bar() + self.bar()
+    }
+}
+
+pub struct UnitEncoder;
+
+impl SubEncoder for UnitEncoder {
+    type ActualSize = ();
+
+    fn bar(&self) {}
+}
+
+pub fn fun<R: Encoder>(encoder: &R) {
+    encoder.foo();
+}
+
+fn main() {
+    fun(&UnitEncoder {});
+}
diff --git a/src/test/ui/associated-types/issue-54108.stderr b/src/test/ui/associated-types/issue-54108.stderr
new file mode 100644
index 0000000..927a2de
--- /dev/null
+++ b/src/test/ui/associated-types/issue-54108.stderr
@@ -0,0 +1,18 @@
+error[E0277]: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize`
+  --> $DIR/issue-54108.rs:19:5
+   |
+LL |     type Size: Add<Output = Self::Size>;
+   |                ------------------------ required by this bound in `Encoder::Size`
+...
+LL |     type Size = <Self as SubEncoder>::ActualSize;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `<T as SubEncoder>::ActualSize + <T as SubEncoder>::ActualSize`
+   |
+   = help: the trait `Add` is not implemented for `<T as SubEncoder>::ActualSize`
+help: consider further restricting the associated type
+   |
+LL |     T: SubEncoder, <T as SubEncoder>::ActualSize: Add
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr
index ddc0bf4..16ae076 100644
--- a/src/test/ui/associated-types/issue-63593.stderr
+++ b/src/test/ui/associated-types/issue-63593.stderr
@@ -1,10 +1,11 @@
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
   --> $DIR/issue-63593.rs:9:5
    |
-LL | trait MyTrait {
-   | ------------- required by `MyTrait`
 LL |     type This = Self;
-   |     ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |     ^^^^^^^^^^^^^^^^^
+   |     |
+   |     doesn't have a size known at compile-time
+   |     required by this bound in `MyTrait::This`
    |
 help: consider further restricting `Self`
    |
diff --git a/src/test/ui/associated-types/issue-65774-1.rs b/src/test/ui/associated-types/issue-65774-1.rs
index 0ffd6cc..9345140 100644
--- a/src/test/ui/associated-types/issue-65774-1.rs
+++ b/src/test/ui/associated-types/issue-65774-1.rs
@@ -14,7 +14,6 @@
 struct S;
 
 impl MPU for S { }
-//~^ ERROR the trait bound `T: MyDisplay` is not satisfied
 
 trait MyWrite {
     fn my_write(&self, _: &dyn MyDisplay) { }
@@ -43,6 +42,7 @@
         // FulfillmentError(Obligation(predicate=Binder(TraitPredicate(<T as MyDisplay>)),
         // depth=1),Unimplemented)
         let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config);
+        //~^ ERROR the trait bound `T: MyDisplay` is not satisfied
         closure(valref);
     }
 }
diff --git a/src/test/ui/associated-types/issue-65774-1.stderr b/src/test/ui/associated-types/issue-65774-1.stderr
index 72f47df..f644eb5 100644
--- a/src/test/ui/associated-types/issue-65774-1.stderr
+++ b/src/test/ui/associated-types/issue-65774-1.stderr
@@ -1,21 +1,20 @@
 error[E0277]: the trait bound `T: MyDisplay` is not satisfied
-  --> $DIR/issue-65774-1.rs:10:21
+  --> $DIR/issue-65774-1.rs:10:5
    |
-LL | trait MPU {
-   | --------- required by `MPU`
 LL |     type MpuConfig: MyDisplay = T;
-   |                     ^^^^^^^^^ the trait `MyDisplay` is not implemented for `T`
+   |     ^^^^^^^^^^^^^^^^---------^^^^^
+   |     |               |
+   |     |               required by this bound in `MPU::MpuConfig`
+   |     the trait `MyDisplay` is not implemented for `T`
 
 error[E0277]: the trait bound `T: MyDisplay` is not satisfied
-  --> $DIR/issue-65774-1.rs:16:6
+  --> $DIR/issue-65774-1.rs:44:76
    |
-LL | trait MPU {
-   |       --- required by a bound in this
-LL |     type MpuConfig: MyDisplay = T;
-   |                     --------- required by this bound in `MPU`
-...
-LL | impl MPU for S { }
-   |      ^^^ the trait `MyDisplay` is not implemented for `T`
+LL |         let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config);
+   |                                                                            ^^^^^^^ the trait `MyDisplay` is not implemented for `T`
+   |
+   = note: required because of the requirements on the impl of `MyDisplay` for `&mut T`
+   = note: required for the cast to the object type `dyn MyDisplay`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/issue-65774-2.rs b/src/test/ui/associated-types/issue-65774-2.rs
index 31e203a..171e0893 100644
--- a/src/test/ui/associated-types/issue-65774-2.rs
+++ b/src/test/ui/associated-types/issue-65774-2.rs
@@ -14,7 +14,6 @@
 struct S;
 
 impl MPU for S { }
-//~^ ERROR the trait bound `T: MyDisplay` is not satisfied
 
 trait MyWrite {
     fn my_write(&self, _: &dyn MyDisplay) { }
@@ -38,6 +37,7 @@
         // // `Unimplemented` selecting `Binder(<T as MyDisplay>)` during codegen
         //
         writer.my_write(valref)
+        //~^ ERROR the trait bound `T: MyDisplay` is not satisfied
 
         // This one causes the ICE:
         // FulfillmentError(Obligation(predicate=Binder(TraitPredicate(<T as MyDisplay>)),
diff --git a/src/test/ui/associated-types/issue-65774-2.stderr b/src/test/ui/associated-types/issue-65774-2.stderr
index aef7088..572a9cf 100644
--- a/src/test/ui/associated-types/issue-65774-2.stderr
+++ b/src/test/ui/associated-types/issue-65774-2.stderr
@@ -1,21 +1,19 @@
 error[E0277]: the trait bound `T: MyDisplay` is not satisfied
-  --> $DIR/issue-65774-2.rs:10:21
+  --> $DIR/issue-65774-2.rs:10:5
    |
-LL | trait MPU {
-   | --------- required by `MPU`
 LL |     type MpuConfig: MyDisplay = T;
-   |                     ^^^^^^^^^ the trait `MyDisplay` is not implemented for `T`
+   |     ^^^^^^^^^^^^^^^^---------^^^^^
+   |     |               |
+   |     |               required by this bound in `MPU::MpuConfig`
+   |     the trait `MyDisplay` is not implemented for `T`
 
 error[E0277]: the trait bound `T: MyDisplay` is not satisfied
-  --> $DIR/issue-65774-2.rs:16:6
+  --> $DIR/issue-65774-2.rs:39:25
    |
-LL | trait MPU {
-   |       --- required by a bound in this
-LL |     type MpuConfig: MyDisplay = T;
-   |                     --------- required by this bound in `MPU`
-...
-LL | impl MPU for S { }
-   |      ^^^ the trait `MyDisplay` is not implemented for `T`
+LL |         writer.my_write(valref)
+   |                         ^^^^^^ the trait `MyDisplay` is not implemented for `T`
+   |
+   = note: required for the cast to the object type `dyn MyDisplay`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/issue-65934.rs b/src/test/ui/associated-types/issue-65934.rs
new file mode 100644
index 0000000..e17b11c
--- /dev/null
+++ b/src/test/ui/associated-types/issue-65934.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+trait Trait {
+    type Assoc;
+}
+
+impl Trait for () {
+    type Assoc = ();
+}
+
+fn unit() -> impl Into<<() as Trait>::Assoc> {}
+
+pub fn ice() {
+    Into::into(unit());
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-72806.rs b/src/test/ui/associated-types/issue-72806.rs
index ae63781..9475825 100644
--- a/src/test/ui/associated-types/issue-72806.rs
+++ b/src/test/ui/associated-types/issue-72806.rs
@@ -9,9 +9,10 @@
 struct Foo;
 struct Foo2;
 
-impl Bar for Foo {  //~ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == char`
+impl Bar for Foo {
     type Ok = ();
     type Sibling = Foo2;
+    //~^ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == char`
 }
 impl Bar2 for Foo2 {
     type Ok = u32;
diff --git a/src/test/ui/associated-types/issue-72806.stderr b/src/test/ui/associated-types/issue-72806.stderr
index 03a6565..23fabbe 100644
--- a/src/test/ui/associated-types/issue-72806.stderr
+++ b/src/test/ui/associated-types/issue-72806.stderr
@@ -1,8 +1,11 @@
 error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == char`
-  --> $DIR/issue-72806.rs:12:6
+  --> $DIR/issue-72806.rs:14:5
    |
-LL | impl Bar for Foo {
-   |      ^^^ expected `u32`, found `char`
+LL |     type Sibling: Bar2<Ok=char>;
+   |                        ------- required by this bound in `Bar::Sibling`
+...
+LL |     type Sibling = Foo2;
+   |     ^^^^^^^^^^^^^^^^^^^^ expected `char`, found `u32`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/normalization-probe-cycle.rs b/src/test/ui/associated-types/normalization-probe-cycle.rs
new file mode 100644
index 0000000..9c1a488
--- /dev/null
+++ b/src/test/ui/associated-types/normalization-probe-cycle.rs
@@ -0,0 +1,25 @@
+// Regression test for #77656
+
+// check-pass
+
+trait Value: PartialOrd {}
+
+impl<T: PartialOrd> Value for T {}
+
+trait Distance
+where
+    Self: PartialOrd<<Self as Distance>::Value>,
+    Self: PartialOrd,
+{
+    type Value: Value;
+}
+
+impl<T: Value> Distance for T {
+    type Value = T;
+}
+
+trait Proximity<T = Self> {
+    type Distance: Distance;
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/object-normalization.rs b/src/test/ui/associated-types/object-normalization.rs
new file mode 100644
index 0000000..1f93248
--- /dev/null
+++ b/src/test/ui/associated-types/object-normalization.rs
@@ -0,0 +1,26 @@
+// ignore-tidy-linelength
+
+// Check that we normalize super predicates for object candidates.
+
+// check-pass
+
+use std::ops::Index;
+
+fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+    // To prove
+    // `dyn SVec<Item = T, Output = T>: SVec`
+    // we need to show
+    // `dyn SVec<Item = T, Output = T> as Index>::Output == <dyn SVec<Item = T, Output = T> as SVec>::Item`
+    // which, with the current normalization strategy, has to be eagerly
+    // normalized to:
+    // `dyn SVec<Item = T, Output = T> as Index>::Output == T`.
+    let _ = s.len();
+}
+
+trait SVec: Index<usize, Output = <Self as SVec>::Item> {
+    type Item;
+
+    fn len(&self) -> usize;
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/param-env-normalize-cycle.rs b/src/test/ui/associated-types/param-env-normalize-cycle.rs
new file mode 100644
index 0000000..12db595
--- /dev/null
+++ b/src/test/ui/associated-types/param-env-normalize-cycle.rs
@@ -0,0 +1,39 @@
+// Minimized case from typenum that didn't compile because:
+// - We tried to normalize the ParamEnv of the second impl
+// - This requires trying to normalize `GrEq<Self, Square<Square<U>>>`
+// - This requires proving `Square<Square<U>>: Sized` so that the first impl
+//   applies
+// - This requires Providing `Square<Square<U>>` is well-formed, so that we
+//   can use the `Sized` bound on `Mul::Output`
+// - This requires proving `Square<U>: Mul`
+// - But first we tried normalizing the whole obligation, including the
+//   ParamEnv, which leads to a cycle error.
+
+// check-pass
+
+trait PrivateSquareRoot {}
+
+pub trait Mul<Rhs = Self> {
+    type Output;
+}
+
+pub trait IsGreaterOrEqual<Rhs> {
+    type Output;
+}
+
+pub type Square<A> = <A as Mul>::Output;
+pub type GrEq<A, B> = <A as IsGreaterOrEqual<B>>::Output;
+
+impl<A, B> IsGreaterOrEqual<B> for A {
+    type Output = ();
+}
+
+impl<U> PrivateSquareRoot for U
+where
+    U: Mul,
+    Square<U>: Mul,
+    GrEq<Self, Square<Square<U>>>: Sized,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs
index 67b7c78..4b3d6e9 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs
@@ -8,7 +8,10 @@
     type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
 }
 
-trait Baz where Self::Assoc: Bar {
+trait Baz
+where
+    Self::Assoc: Bar,
+{
     type Assoc;
 }
 
@@ -16,7 +19,10 @@
     type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
 }
 
-trait Bat where <Self as Bat>::Assoc: Bar {
+trait Bat
+where
+    <Self as Bat>::Assoc: Bar,
+{
     type Assoc;
 }
 
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
index 3118a9c..b23030d 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
@@ -1,31 +1,35 @@
 error[E0277]: the trait bound `bool: Bar` is not satisfied
-  --> $DIR/point-at-type-on-obligation-failure-2.rs:8:18
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
    |
-LL | trait Foo {
-   |       --- required by a bound in this
 LL |     type Assoc: Bar;
-   |                 --- required by this bound in `Foo`
+   |                 --- required by this bound in `Foo::Assoc`
 ...
 LL |     type Assoc = bool;
-   |                  ^^^^ the trait `Bar` is not implemented for `bool`
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
 
 error[E0277]: the trait bound `bool: Bar` is not satisfied
-  --> $DIR/point-at-type-on-obligation-failure-2.rs:16:18
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:19:5
    |
-LL | trait Baz where Self::Assoc: Bar {
-   |                              --- required by this bound in `Baz`
+LL |     Self::Assoc: Bar,
+   |                  --- required by this bound in `Baz::Assoc`
+LL | {
+LL |     type Assoc;
+   |          ----- required by a bound in this
 ...
 LL |     type Assoc = bool;
-   |                  ^^^^ the trait `Bar` is not implemented for `bool`
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
 
 error[E0277]: the trait bound `bool: Bar` is not satisfied
-  --> $DIR/point-at-type-on-obligation-failure-2.rs:24:18
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:30:5
    |
-LL | trait Bat where <Self as Bat>::Assoc: Bar {
-   |                                       --- required by this bound in `Bat`
+LL |     <Self as Bat>::Assoc: Bar,
+   |                           --- required by this bound in `Bat::Assoc`
+LL | {
+LL |     type Assoc;
+   |          ----- required by a bound in this
 ...
 LL |     type Assoc = bool;
-   |                  ^^^^ the trait `Bar` is not implemented for `bool`
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure.rs b/src/test/ui/associated-types/point-at-type-on-obligation-failure.rs
index dc43dba..6666600 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure.rs
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure.rs
@@ -10,8 +10,9 @@
 struct Foo2;
 
 impl Bar for Foo {
-    type Ok = ();  //~ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
+    type Ok = ();
     type Sibling = Foo2;
+    //~^ ERROR type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
 }
 impl Bar2 for Foo2 {
     type Ok = u32;
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr b/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr
index 818702b7..7417a5a 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr
@@ -1,8 +1,11 @@
 error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
-  --> $DIR/point-at-type-on-obligation-failure.rs:13:15
+  --> $DIR/point-at-type-on-obligation-failure.rs:14:5
    |
-LL |     type Ok = ();
-   |               ^^ expected `u32`, found `()`
+LL |     type Sibling: Bar2<Ok=Self::Ok>;
+   |                        ----------- required by this bound in `Bar::Sibling`
+...
+LL |     type Sibling = Foo2;
+   |     ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u32`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/wf-cycle-2.rs b/src/test/ui/associated-types/wf-cycle-2.rs
new file mode 100644
index 0000000..d7467ac
--- /dev/null
+++ b/src/test/ui/associated-types/wf-cycle-2.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+trait IntoIt {
+    type Item;
+}
+
+impl<I> IntoIt for I {
+    type Item = ();
+}
+
+trait BaseGraph
+where
+    <Self::VertexIter as IntoIt>::Item: Sized,
+{
+    type VertexIter: IntoIt;
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/wf-cycle.rs b/src/test/ui/associated-types/wf-cycle.rs
new file mode 100644
index 0000000..cf65085
--- /dev/null
+++ b/src/test/ui/associated-types/wf-cycle.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+trait A {
+    type U: Copy;
+}
+
+trait B where
+    <Self::V as A>::U: Copy,
+{
+    type V: A;
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr
index d808a59..994bfd3 100644
--- a/src/test/ui/async-await/async-error-span.stderr
+++ b/src/test/ui/async-await/async-error-span.stderr
@@ -3,12 +3,8 @@
    |
 LL | fn get_future() -> impl Future<Output = ()> {
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
-LL |
-LL |     panic!()
-   |     -------- this returned value is of type `!`
    |
    = help: the trait `Future` is not implemented for `()`
-   = note: the return type of a function must have a statically known size
 
 error[E0698]: type inside `async fn` body must be known in this context
   --> $DIR/async-error-span.rs:13:9
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
index f1f1b2d..88ea725 100644
--- a/src/test/ui/async-await/issue-61076.stderr
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -27,33 +27,18 @@
    |
 LL |     let _: i32 = tuple().0;
    |                          ^
-   |
-help: consider awaiting before field access
-   |
-LL |     let _: i32 = tuple().await.0;
-   |                         ^^^^^^
 
 error[E0609]: no field `a` on type `impl Future`
   --> $DIR/issue-61076.rs:60:28
    |
 LL |     let _: i32 = struct_().a;
    |                            ^
-   |
-help: consider awaiting before field access
-   |
-LL |     let _: i32 = struct_().await.a;
-   |                           ^^^^^^
 
 error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope
   --> $DIR/issue-61076.rs:62:15
    |
 LL |     struct_().method();
    |               ^^^^^^ method not found in `impl Future`
-   |
-help: consider awaiting before this method call
-   |
-LL |     struct_().await.method();
-   |               ^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-61076.rs:69:9
@@ -66,10 +51,6 @@
    |
    = note: expected opaque type `impl Future`
                    found struct `Tuple`
-help: consider awaiting on the future
-   |
-LL |     match tuple().await {
-   |                  ^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr
index 440ea0a..2d46dfb 100644
--- a/src/test/ui/async-await/issue-64130-4-async-move.stderr
+++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr
@@ -1,17 +1,8 @@
 error: future cannot be sent between threads safely
   --> $DIR/issue-64130-4-async-move.rs:15:17
    |
-LL |   pub fn foo() -> impl Future + Send {
-   |                   ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
-...
-LL | /     async move {
-LL | |         match client.status() {
-LL | |             200 => {
-LL | |                 let _x = get().await;
-...  |
-LL | |         }
-LL | |     }
-   | |_____- this returned value is of type `impl Future`
+LL | pub fn foo() -> impl Future + Send {
+   |                 ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
    |
    = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
 note: future is not `Send` as this value is used across an await
@@ -30,7 +21,6 @@
    |
 LL |         match client.status() {
    |               ^^^^^^^^^^^^^^^
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.stderr b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr
index 7825304..832b736 100644
--- a/src/test/ui/async-await/issue-67765-async-diagnostic.stderr
+++ b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr
@@ -1,11 +1,11 @@
 error[E0515]: cannot return value referencing local variable `s`
-  --> $DIR/issue-67765-async-diagnostic.rs:13:11
+  --> $DIR/issue-67765-async-diagnostic.rs:13:5
    |
 LL |     let b = &s[..];
    |              - `s` is borrowed here
 LL | 
 LL |     Err(b)?;
-   |           ^ returns a value referencing data owned by the current function
+   |     ^^^^^^^ returns a value referencing data owned by the current function
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr
index 07269f7..e97d088 100644
--- a/src/test/ui/async-await/issue-68112.stderr
+++ b/src/test/ui/async-await/issue-68112.stderr
@@ -41,8 +41,8 @@
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
-   = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:Arc<RefCell<i32>> {}]`
-   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:Arc<RefCell<i32>> {}]>`
+   = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]`
+   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]>`
    = note: required because it appears within the type `impl Future`
    = note: required because it appears within the type `impl Future`
    = note: required because it appears within the type `impl Future`
diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr
index 364194b..11fca2d 100644
--- a/src/test/ui/async-await/issue-70818.stderr
+++ b/src/test/ui/async-await/issue-70818.stderr
@@ -3,16 +3,12 @@
    |
 LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
-LL |
-LL |     async { (ty, ty1) }
-   |     ------------------- this returned value is of type `impl Future`
    |
 note: captured value is not `Send`
   --> $DIR/issue-70818.rs:6:18
    |
 LL |     async { (ty, ty1) }
    |                  ^^^ has type `U` which is not `Send`
-   = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `U`
    |
 LL | fn foo<T: Send, U: Send>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs
index 2f80435..4f160fc 100644
--- a/src/test/ui/async-await/issues/issue-65159.rs
+++ b/src/test/ui/async-await/issues/issue-65159.rs
@@ -5,7 +5,7 @@
 async fn copy() -> Result<()> //~ ERROR wrong number of type arguments
 {
     Ok(())
-    //~^ type annotations needed
+    //~^ ERROR type annotations needed
 }
 
 fn main() { }
diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs
index 57a9f17..b3c5973 100644
--- a/src/test/ui/async-await/no-const-async.rs
+++ b/src/test/ui/async-await/no-const-async.rs
@@ -3,4 +3,3 @@
 
 pub const async fn x() {}
 //~^ ERROR functions cannot be both `const` and `async`
-//~| ERROR `impl Trait` in const fn is unstable
diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr
index 4e59bb5..90ec646 100644
--- a/src/test/ui/async-await/no-const-async.stderr
+++ b/src/test/ui/async-await/no-const-async.stderr
@@ -7,15 +7,5 @@
    |     |     `async` because of this
    |     `const` because of this
 
-error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/no-const-async.rs:4:24
-   |
-LL | pub const async fn x() {}
-   |                        ^
-   |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/auxiliary/issue-72470-lib.rs b/src/test/ui/auxiliary/issue-72470-lib.rs
new file mode 100644
index 0000000..8383eba
--- /dev/null
+++ b/src/test/ui/auxiliary/issue-72470-lib.rs
@@ -0,0 +1,175 @@
+// compile-flags: -C opt-level=3
+// edition:2018
+
+use std::future::Future;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::sync::atomic::AtomicUsize;
+use std::sync::Arc;
+use std::task::Poll::{Pending, Ready};
+use std::task::Waker;
+use std::task::{Context, Poll};
+use std::{
+    ptr,
+    task::{RawWaker, RawWakerVTable},
+};
+
+/// Future for the [`poll_fn`] function.
+pub struct PollFn<F> {
+    f: F,
+}
+
+impl<F> Unpin for PollFn<F> {}
+
+/// Creates a new future wrapping around a function returning [`Poll`].
+pub fn poll_fn<T, F>(f: F) -> PollFn<F>
+where
+    F: FnMut(&mut Context<'_>) -> Poll<T>,
+{
+    PollFn { f }
+}
+
+impl<T, F> Future for PollFn<F>
+where
+    F: FnMut(&mut Context<'_>) -> Poll<T>,
+{
+    type Output = T;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
+        (&mut self.f)(cx)
+    }
+}
+pub fn run<F: Future>(future: F) -> F::Output {
+    BasicScheduler.block_on(future)
+}
+
+pub(crate) struct BasicScheduler;
+
+impl BasicScheduler {
+    pub(crate) fn block_on<F>(&mut self, mut future: F) -> F::Output
+    where
+        F: Future,
+    {
+        let waker = unsafe { Waker::from_raw(raw_waker()) };
+        let mut cx = std::task::Context::from_waker(&waker);
+
+        let mut future = unsafe { Pin::new_unchecked(&mut future) };
+
+        loop {
+            if let Ready(v) = future.as_mut().poll(&mut cx) {
+                return v;
+            }
+        }
+    }
+}
+
+// ===== impl Spawner =====
+
+fn raw_waker() -> RawWaker {
+    RawWaker::new(ptr::null(), waker_vtable())
+}
+
+fn waker_vtable() -> &'static RawWakerVTable {
+    &RawWakerVTable::new(
+        clone_arc_raw,
+        wake_arc_raw,
+        wake_by_ref_arc_raw,
+        drop_arc_raw,
+    )
+}
+
+unsafe fn clone_arc_raw(_: *const ()) -> RawWaker {
+    raw_waker()
+}
+
+unsafe fn wake_arc_raw(_: *const ()) {}
+
+unsafe fn wake_by_ref_arc_raw(_: *const ()) {}
+
+unsafe fn drop_arc_raw(_: *const ()) {}
+
+struct AtomicWaker {}
+
+impl AtomicWaker {
+    /// Create an `AtomicWaker`
+    fn new() -> AtomicWaker {
+        AtomicWaker {}
+    }
+
+    fn register_by_ref(&self, _waker: &Waker) {}
+}
+
+#[allow(dead_code)]
+struct Tx<T> {
+    inner: Arc<Chan<T>>,
+}
+
+struct Rx<T> {
+    inner: Arc<Chan<T>>,
+}
+
+#[allow(dead_code)]
+struct Chan<T> {
+    tx: PhantomData<T>,
+    semaphore: Sema,
+    rx_waker: AtomicWaker,
+    rx_closed: bool,
+}
+
+fn channel<T>() -> (Tx<T>, Rx<T>) {
+    let chan = Arc::new(Chan {
+        tx: PhantomData,
+        semaphore: Sema(AtomicUsize::new(0)),
+        rx_waker: AtomicWaker::new(),
+        rx_closed: false,
+    });
+
+    (
+        Tx {
+            inner: chan.clone(),
+        },
+        Rx { inner: chan },
+    )
+}
+
+// ===== impl Rx =====
+
+impl<T> Rx<T> {
+    /// Receive the next value
+    fn recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
+        self.inner.rx_waker.register_by_ref(cx.waker());
+
+        if self.inner.rx_closed && self.inner.semaphore.is_idle() {
+            Ready(None)
+        } else {
+            Pending
+        }
+    }
+}
+
+struct Sema(AtomicUsize);
+
+impl Sema {
+    fn is_idle(&self) -> bool {
+        false
+    }
+}
+
+pub struct UnboundedReceiver<T> {
+    chan: Rx<T>,
+}
+
+pub fn unbounded_channel<T>() -> UnboundedReceiver<T> {
+    let (tx, rx) = channel();
+
+    drop(tx);
+    let rx = UnboundedReceiver { chan: rx };
+
+    rx
+}
+
+impl<T> UnboundedReceiver<T> {
+    pub async fn recv(&mut self) -> Option<T> {
+        poll_fn(|cx| self.chan.recv(cx)).await
+    }
+}
diff --git a/src/test/ui/binding/const-param.stderr b/src/test/ui/binding/const-param.stderr
index 316fac6..d3d06a2 100644
--- a/src/test/ui/binding/const-param.stderr
+++ b/src/test/ui/binding/const-param.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0158]: const parameters cannot be referenced in patterns
   --> $DIR/const-param.rs:7:9
diff --git a/src/test/ui/binop/binop-mul-bool.rs b/src/test/ui/binop/binop-mul-bool.rs
index 27b2f8b..41494c7 100644
--- a/src/test/ui/binop/binop-mul-bool.rs
+++ b/src/test/ui/binop/binop-mul-bool.rs
@@ -1,3 +1,3 @@
-// error-pattern:cannot multiply `bool` to `bool`
+// error-pattern:cannot multiply `bool` by `bool`
 
 fn main() { let x = true * false; }
diff --git a/src/test/ui/binop/binop-mul-bool.stderr b/src/test/ui/binop/binop-mul-bool.stderr
index 859c44a..8b5cde6 100644
--- a/src/test/ui/binop/binop-mul-bool.stderr
+++ b/src/test/ui/binop/binop-mul-bool.stderr
@@ -1,4 +1,4 @@
-error[E0369]: cannot multiply `bool` to `bool`
+error[E0369]: cannot multiply `bool` by `bool`
   --> $DIR/binop-mul-bool.rs:3:26
    |
 LL | fn main() { let x = true * false; }
diff --git a/src/test/ui/binop/binop-mul-i32-f32.rs b/src/test/ui/binop/binop-mul-i32-f32.rs
new file mode 100644
index 0000000..d18be51
--- /dev/null
+++ b/src/test/ui/binop/binop-mul-i32-f32.rs
@@ -0,0 +1,5 @@
+fn foo(x: i32, y: f32) -> f32 {
+    x * y //~ ERROR cannot multiply `i32` by `f32`
+}
+
+fn main() {}
diff --git a/src/test/ui/binop/binop-mul-i32-f32.stderr b/src/test/ui/binop/binop-mul-i32-f32.stderr
new file mode 100644
index 0000000..4a67fe2
--- /dev/null
+++ b/src/test/ui/binop/binop-mul-i32-f32.stderr
@@ -0,0 +1,11 @@
+error[E0277]: cannot multiply `i32` by `f32`
+  --> $DIR/binop-mul-i32-f32.rs:2:7
+   |
+LL |     x * y
+   |       ^ no implementation for `i32 * f32`
+   |
+   = help: the trait `Mul<f32>` is not implemented for `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr
index 560c9c2..09c06e8 100644
--- a/src/test/ui/block-result/issue-20862.stderr
+++ b/src/test/ui/block-result/issue-20862.stderr
@@ -7,7 +7,7 @@
    |     ^^^^^^^^^ expected `()`, found closure
    |
    = note: expected unit type `()`
-                found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]`
+                found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14]`
 
 error[E0618]: expected function, found `()`
   --> $DIR/issue-20862.rs:7:13
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
index b67d494..97f96ab 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
@@ -3,8 +3,6 @@
 #![feature(or_patterns)]
 #![feature(box_patterns)]
 
-#![feature(move_ref_pattern)]
-
 enum Test {
     Foo,
     Bar,
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
index 1bf8158..96e313b 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -1,5 +1,5 @@
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:40:9
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:38:9
    |
 LL |         ref foo @ [.., ref mut bar] => (),
    |         -------^^^^^^^^-----------^
@@ -8,7 +8,7 @@
    |         immutable borrow, by `foo`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:124:9
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:122:9
    |
 LL |         ref foo @ Some(box ref mut s) => (),
    |         -------^^^^^^^^^^^^---------^
@@ -17,7 +17,7 @@
    |         immutable borrow, by `foo`, occurs here
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:20:5
    |
 LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
    |                                                  - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait
@@ -29,7 +29,7 @@
    |     ^^ value borrowed here after move
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:32:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:30:5
    |
 LL |         ref mut foo @ [.., _] => Some(foo),
    |         --------------------- mutable borrow occurs here
@@ -41,7 +41,7 @@
    |          - mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:54:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:52:5
    |
 LL |         [ref foo @ .., ref bar] => Some(foo),
    |          ------------ immutable borrow occurs here
@@ -53,7 +53,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:66:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:64:5
    |
 LL |         ref foo @ [.., ref bar] => Some(foo),
    |         ----------------------- immutable borrow occurs here
@@ -65,7 +65,7 @@
    |          - immutable borrow later used here
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:78:5
    |
 LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
    |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
@@ -80,7 +80,7 @@
    |     ^^ value borrowed here after move
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:90:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:88:5
    |
 LL |         ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
    |         ------------------------------------- immutable borrow occurs here
@@ -92,7 +92,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:102:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:100:5
    |
 LL |         ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
    |         ----------------------------------------- mutable borrow occurs here
@@ -104,7 +104,7 @@
    |          - mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:116:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:114:5
    |
 LL |         ref foo @ Some(box ref s) => Some(foo),
    |         ------------------------- immutable borrow occurs here
@@ -116,7 +116,7 @@
    |          - immutable borrow later used here
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:136:5
    |
 LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) {
    |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
@@ -131,7 +131,7 @@
    |     ^^ value borrowed here after move
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:148:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:146:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
    |         ------------------------------------------------- immutable borrow occurs here
@@ -143,7 +143,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:160:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:158:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
    |                  ---------- immutable borrow occurs here
@@ -155,7 +155,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:174:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:172:5
    |
 LL |         [_, ref a @ Some(box ref b), ..] => Some(a),
    |             ----------------------- immutable borrow occurs here
@@ -167,7 +167,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:190:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:188:5
    |
 LL |         [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
    |             ------------------------------------------- immutable borrow occurs here
@@ -179,7 +179,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:204:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:202:5
    |
 LL |         [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
    |             ----------------------------------------------- mutable borrow occurs here
@@ -191,7 +191,7 @@
    |          - mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:218:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:216:5
    |
 LL |         ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
    |         ------------------------------------------------------------ immutable borrow occurs here
diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
index 3781691..e8a026c 100644
--- a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
+++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
@@ -4,7 +4,7 @@
 LL |     let _action = move || {
    |                   -------
    |                   |     |
-   |                   |     return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15 f:&'2 [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:2:13: 2:23]]
+   |                   |     return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15]
    |                   lifetime `'1` represents this closure's body
 LL |         || f() // The `nested` closure
    |         ^^^^^^ returning this value requires that `'1` must outlive `'2`
diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs b/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
index 212f706..59b541a 100644
--- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
+++ b/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
@@ -1,11 +1,11 @@
 // Suggest not mutably borrowing a mutable reference
+#![crate_type = "rlib"]
 
-fn main() {
-    f(&mut 0)
+pub fn f(b: &mut i32) {
+    g(&mut b);
+    //~^ ERROR cannot borrow
+    g(&mut &mut b);
+    //~^ ERROR cannot borrow
 }
 
-fn f(b: &mut i32) {
-    g(&mut b) //~ ERROR cannot borrow
-}
-
-fn g(_: &mut i32) {}
+pub fn g(_: &mut i32) {}
diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
index 09dabbc..8710f20 100644
--- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
+++ b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
@@ -1,11 +1,21 @@
 error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:8:7
+  --> $DIR/mut-borrow-of-mut-ref.rs:5:7
    |
-LL | fn f(b: &mut i32) {
-   |      - help: consider changing this to be mutable: `mut b`
-LL |     g(&mut b)
-   |       ^^^^^^ cannot borrow as mutable
+LL |     g(&mut b);
+   |       ^^^^^^
+   |       |
+   |       cannot borrow as mutable
+   |       try removing `&mut` here
 
-error: aborting due to previous error
+error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
+  --> $DIR/mut-borrow-of-mut-ref.rs:7:12
+   |
+LL |     g(&mut &mut b);
+   |            ^^^^^^
+   |            |
+   |            cannot borrow as mutable
+   |            try removing `&mut` here
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr
index 89ea65f..6f2a6c3 100644
--- a/src/test/ui/c-variadic/variadic-ffi-1.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr
@@ -7,24 +7,30 @@
 error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied
   --> $DIR/variadic-ffi-1.rs:17:9
    |
-LL |     fn foo(f: isize, x: u8, ...);
-   |     ----------------------------- defined here
-...
 LL |         foo();
    |         ^^^-- supplied 0 arguments
    |         |
    |         expected at least 2 arguments
+   |
+note: function defined here
+  --> $DIR/variadic-ffi-1.rs:10:8
+   |
+LL |     fn foo(f: isize, x: u8, ...);
+   |        ^^^
 
 error[E0060]: this function takes at least 2 arguments but 1 argument was supplied
   --> $DIR/variadic-ffi-1.rs:18:9
    |
-LL |     fn foo(f: isize, x: u8, ...);
-   |     ----------------------------- defined here
-...
 LL |         foo(1);
    |         ^^^ - supplied 1 argument
    |         |
    |         expected at least 2 arguments
+   |
+note: function defined here
+  --> $DIR/variadic-ffi-1.rs:10:8
+   |
+LL |     fn foo(f: isize, x: u8, ...);
+   |        ^^^
 
 error[E0308]: mismatched types
   --> $DIR/variadic-ffi-1.rs:20:56
diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
index 7af38c8..e11ba43 100644
--- a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
@@ -2,7 +2,7 @@
   --> $DIR/variadic-ffi-no-fixed-args.rs:2:12
    |
 LL |     fn foo(...);
-   |            ^^^^
+   |            ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/cell-does-not-clone.rs b/src/test/ui/cell-does-not-clone.rs
deleted file mode 100644
index 587447b..0000000
--- a/src/test/ui/cell-does-not-clone.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-
-use std::cell::Cell;
-
-#[derive(Copy)]
-struct Foo {
-    x: isize
-}
-
-impl Clone for Foo {
-    fn clone(&self) -> Foo {
-        // Using Cell in any way should never cause clone() to be
-        // invoked -- after all, that would permit evil user code to
-        // abuse `Cell` and trigger crashes.
-
-        panic!();
-    }
-}
-
-pub fn main() {
-    let x = Cell::new(Foo { x: 22 });
-    let _y = x.get();
-    let _z = x.clone();
-}
diff --git a/src/test/ui/chalkify/impl_wf.rs b/src/test/ui/chalkify/impl_wf.rs
index 465eb10..66f57c2 100644
--- a/src/test/ui/chalkify/impl_wf.rs
+++ b/src/test/ui/chalkify/impl_wf.rs
@@ -15,19 +15,6 @@
 // Implicit `T: Sized` bound.
 impl<T> Foo for Option<T> { }
 
-impl Bar for () {
-    type Item = i32;
-}
-
-impl<T> Bar for Option<T> {
-    type Item = Option<T>;
-}
-
-impl Bar for f32 {
-    type Item = f32;
-    //~^ ERROR the trait bound `f32: Foo` is not satisfied
-}
-
 trait Baz<U: ?Sized> where U: Foo { }
 
 impl Baz<i32> for i32 { }
diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr
index 4ca5ae4..24c7f0d 100644
--- a/src/test/ui/chalkify/impl_wf.stderr
+++ b/src/test/ui/chalkify/impl_wf.stderr
@@ -10,18 +10,7 @@
    = help: the trait `Sized` is not implemented for `str`
 
 error[E0277]: the trait bound `f32: Foo` is not satisfied
-  --> $DIR/impl_wf.rs:27:17
-   |
-LL | trait Bar {
-   |       --- required by a bound in this
-LL |     type Item: Foo;
-   |                --- required by this bound in `Bar`
-...
-LL |     type Item = f32;
-   |                 ^^^ the trait `Foo` is not implemented for `f32`
-
-error[E0277]: the trait bound `f32: Foo` is not satisfied
-  --> $DIR/impl_wf.rs:35:6
+  --> $DIR/impl_wf.rs:22:6
    |
 LL | trait Baz<U: ?Sized> where U: Foo { }
    |                               --- required by this bound in `Baz`
@@ -29,6 +18,6 @@
 LL | impl Baz<f32> for f32 { }
    |      ^^^^^^^^ the trait `Foo` is not implemented for `f32`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/chalkify/impl_wf_2.rs b/src/test/ui/chalkify/impl_wf_2.rs
new file mode 100644
index 0000000..758a718
--- /dev/null
+++ b/src/test/ui/chalkify/impl_wf_2.rs
@@ -0,0 +1,33 @@
+// Split out of impl_wf.rs to work around rust aborting compilation early
+
+// compile-flags: -Z chalk
+
+trait Foo: Sized { }
+
+trait Bar {
+    type Item: Foo;
+}
+
+impl Foo for i32 { }
+
+// Implicit `T: Sized` bound.
+impl<T> Foo for Option<T> { }
+
+impl Bar for () {
+    type Item = i32;
+}
+
+impl<T> Bar for Option<T> {
+    type Item = Option<T>;
+}
+
+impl Bar for f32 {
+    type Item = f32;
+    //~^ ERROR the trait bound `f32: Foo` is not satisfied
+}
+
+trait Baz<U: ?Sized> where U: Foo { }
+
+impl Baz<i32> for i32 { }
+
+fn main() {}
diff --git a/src/test/ui/chalkify/impl_wf_2.stderr b/src/test/ui/chalkify/impl_wf_2.stderr
new file mode 100644
index 0000000..1da2144
--- /dev/null
+++ b/src/test/ui/chalkify/impl_wf_2.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `f32: Foo` is not satisfied
+  --> $DIR/impl_wf_2.rs:25:5
+   |
+LL |     type Item: Foo;
+   |                --- required by this bound in `Bar::Item`
+...
+LL |     type Item = f32;
+   |     ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `f32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs
index b02cc1a..0ca2349 100644
--- a/src/test/ui/check-doc-alias-attr.rs
+++ b/src/test/ui/check-doc-alias-attr.rs
@@ -7,4 +7,11 @@
 #[doc(alias)] //~ ERROR
 #[doc(alias = 0)] //~ ERROR
 #[doc(alias("bar"))] //~ ERROR
+#[doc(alias = "\"")] //~ ERROR
+#[doc(alias = "\n")] //~ ERROR
+#[doc(alias = "
+")] //~^ ERROR
+#[doc(alias = "\t")] //~ ERROR
+#[doc(alias = " hello")] //~ ERROR
+#[doc(alias = "hello ")] //~ ERROR
 pub struct Foo;
diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr
index 268230a..2c417a3 100644
--- a/src/test/ui/check-doc-alias-attr.stderr
+++ b/src/test/ui/check-doc-alias-attr.stderr
@@ -16,5 +16,43 @@
 LL | #[doc(alias("bar"))]
    |       ^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: '\"' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:10:7
+   |
+LL | #[doc(alias = "\"")]
+   |       ^^^^^^^^^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:11:7
+   |
+LL | #[doc(alias = "\n")]
+   |       ^^^^^^^^^^^^
+
+error: '\n' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:12:7
+   |
+LL |   #[doc(alias = "
+   |  _______^
+LL | | ")]
+   | |_^
+
+error: '\t' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/check-doc-alias-attr.rs:14:7
+   |
+LL | #[doc(alias = "\t")]
+   |       ^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+  --> $DIR/check-doc-alias-attr.rs:15:7
+   |
+LL | #[doc(alias = " hello")]
+   |       ^^^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+  --> $DIR/check-doc-alias-attr.rs:16:7
+   |
+LL | #[doc(alias = "hello ")]
+   |       ^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/check-static-values-constraints.rs b/src/test/ui/check-static-values-constraints.rs
index acfb3b5..3d1b5a0 100644
--- a/src/test/ui/check-static-values-constraints.rs
+++ b/src/test/ui/check-static-values-constraints.rs
@@ -78,7 +78,6 @@
 
 static STATIC11: Box<MyOwned> = box MyOwned;
 //~^ ERROR allocations are not allowed in statics
-//~| ERROR static contains unimplemented expression type
 
 static mut STATIC12: UnsafeStruct = UnsafeStruct;
 
@@ -93,16 +92,12 @@
 
 static STATIC15: &'static [Box<MyOwned>] = &[
     box MyOwned, //~ ERROR allocations are not allowed in statics
-    //~| ERROR contains unimplemented expression
     box MyOwned, //~ ERROR allocations are not allowed in statics
-    //~| ERROR contains unimplemented expression
 ];
 
 static STATIC16: (&'static Box<MyOwned>, &'static Box<MyOwned>) = (
     &box MyOwned, //~ ERROR allocations are not allowed in statics
-    //~| ERROR contains unimplemented expression
     &box MyOwned, //~ ERROR allocations are not allowed in statics
-    //~| ERROR contains unimplemented expression
 );
 
 static mut STATIC17: SafeEnum = SafeEnum::Variant1;
@@ -110,11 +105,9 @@
 static STATIC19: Box<isize> =
     box 3;
 //~^ ERROR allocations are not allowed in statics
-    //~| ERROR contains unimplemented expression
 
 pub fn main() {
     let y = { static x: Box<isize> = box 3; x };
     //~^ ERROR allocations are not allowed in statics
     //~| ERROR cannot move out of static item
-    //~| ERROR contains unimplemented expression
 }
diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr
index 50c1b50..eb640c8 100644
--- a/src/test/ui/check-static-values-constraints.stderr
+++ b/src/test/ui/check-static-values-constraints.stderr
@@ -15,92 +15,44 @@
 LL | static STATIC11: Box<MyOwned> = box MyOwned;
    |                                 ^^^^^^^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/check-static-values-constraints.rs:79:37
-   |
-LL | static STATIC11: Box<MyOwned> = box MyOwned;
-   |                                     ^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/check-static-values-constraints.rs:90:32
+  --> $DIR/check-static-values-constraints.rs:89:32
    |
 LL |     field2: SafeEnum::Variant4("str".to_string())
    |                                ^^^^^^^^^^^^^^^^^
 
 error[E0010]: allocations are not allowed in statics
+  --> $DIR/check-static-values-constraints.rs:94:5
+   |
+LL |     box MyOwned,
+   |     ^^^^^^^^^^^ allocation not allowed in statics
+
+error[E0010]: allocations are not allowed in statics
   --> $DIR/check-static-values-constraints.rs:95:5
    |
 LL |     box MyOwned,
    |     ^^^^^^^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/check-static-values-constraints.rs:95:9
-   |
-LL |     box MyOwned,
-   |         ^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:97:5
-   |
-LL |     box MyOwned,
-   |     ^^^^^^^^^^^ allocation not allowed in statics
-
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/check-static-values-constraints.rs:97:9
-   |
-LL |     box MyOwned,
-   |         ^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
-error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:102:6
+  --> $DIR/check-static-values-constraints.rs:99:6
    |
 LL |     &box MyOwned,
    |      ^^^^^^^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/check-static-values-constraints.rs:102:10
-   |
-LL |     &box MyOwned,
-   |          ^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:104:6
+  --> $DIR/check-static-values-constraints.rs:100:6
    |
 LL |     &box MyOwned,
    |      ^^^^^^^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/check-static-values-constraints.rs:104:10
-   |
-LL |     &box MyOwned,
-   |          ^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:111:5
+  --> $DIR/check-static-values-constraints.rs:106:5
    |
 LL |     box 3;
    |     ^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/check-static-values-constraints.rs:111:9
-   |
-LL |     box 3;
-   |         ^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0507]: cannot move out of static item `x`
-  --> $DIR/check-static-values-constraints.rs:116:45
+  --> $DIR/check-static-values-constraints.rs:110:45
    |
 LL |     let y = { static x: Box<isize> = box 3; x };
    |                                             ^
@@ -109,20 +61,12 @@
    |                                             help: consider borrowing here: `&x`
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:116:38
+  --> $DIR/check-static-values-constraints.rs:110:38
    |
 LL |     let y = { static x: Box<isize> = box 3; x };
    |                                      ^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/check-static-values-constraints.rs:116:42
-   |
-LL |     let y = { static x: Box<isize> = box 3; x };
-   |                                          ^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+error: aborting due to 10 previous errors
 
-error: aborting due to 17 previous errors
-
-Some errors have detailed explanations: E0010, E0015, E0019, E0493, E0507.
+Some errors have detailed explanations: E0010, E0015, E0493, E0507.
 For more information about an error, try `rustc --explain E0010`.
diff --git a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
index 0c6d11c..2005bd4 100644
--- a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
+++ b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr
@@ -1,8 +1,8 @@
 error[E0282]: type annotations needed
-  --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:5
+  --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27
    |
 LL |     with_closure(|x: u32, y| {});
-   |     ^^^^^^^^^^^^ cannot infer type for type parameter `B` declared on the function `with_closure`
+   |                           ^ consider giving this closure parameter a type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr
index 505cae9..da5e25c 100644
--- a/src/test/ui/closures/closure-move-sync.stderr
+++ b/src/test/ui/closures/closure-move-sync.stderr
@@ -11,7 +11,7 @@
    |
    = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>`
    = note: required because of the requirements on the impl of `Send` for `&std::sync::mpsc::Receiver<()>`
-   = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6 recv:&std::sync::mpsc::Receiver<()>]`
+   = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6]`
 
 error[E0277]: `Sender<()>` cannot be shared between threads safely
   --> $DIR/closure-move-sync.rs:18:5
@@ -26,7 +26,7 @@
    |
    = help: the trait `Sync` is not implemented for `Sender<()>`
    = note: required because of the requirements on the impl of `Send` for `&Sender<()>`
-   = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42 tx:&Sender<()>]`
+   = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/closures/closure-no-fn-1.stderr b/src/test/ui/closures/closure-no-fn-1.stderr
index 5e76ee5..7613631 100644
--- a/src/test/ui/closures/closure-no-fn-1.stderr
+++ b/src/test/ui/closures/closure-no-fn-1.stderr
@@ -7,7 +7,7 @@
    |              expected due to this
    |
    = note: expected fn pointer `fn(u8) -> u8`
-                 found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50 a:_]`
+                 found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-no-fn-2.stderr b/src/test/ui/closures/closure-no-fn-2.stderr
index 07ffd6e..85cbdbe 100644
--- a/src/test/ui/closures/closure-no-fn-2.stderr
+++ b/src/test/ui/closures/closure-no-fn-2.stderr
@@ -7,7 +7,7 @@
    |              expected due to this
    |
    = note: expected fn pointer `fn() -> u8`
-                 found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35 b:_]`
+                 found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr
index 4b3b4be..95683a7 100644
--- a/src/test/ui/closures/closure-no-fn-3.stderr
+++ b/src/test/ui/closures/closure-no-fn-3.stderr
@@ -1,4 +1,4 @@
-error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b:_]` as `fn() -> u8`
+error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37]` as `fn() -> u8`
   --> $DIR/closure-no-fn-3.rs:6:27
    |
 LL |     let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr
index 3c4ae45..77c8c7a 100644
--- a/src/test/ui/closures/closure-reform-bad.stderr
+++ b/src/test/ui/closures/closure-reform-bad.stderr
@@ -7,7 +7,7 @@
    |               ^ expected fn pointer, found closure
    |
    = note: expected fn pointer `for<'r> fn(&'r str)`
-                 found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50 string:_]`
+                 found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-return-type-mismatch.rs b/src/test/ui/closures/closure-return-type-mismatch.rs
new file mode 100644
index 0000000..1631bb3
--- /dev/null
+++ b/src/test/ui/closures/closure-return-type-mismatch.rs
@@ -0,0 +1,17 @@
+fn main() {
+    || {
+        if false {
+            return "test";
+        }
+        let a = true;
+        a //~ ERROR mismatched types
+    };
+
+    || -> bool {
+        if false {
+            return "hello" //~ ERROR mismatched types
+        };
+        let b = true;
+        b
+    };
+}
diff --git a/src/test/ui/closures/closure-return-type-mismatch.stderr b/src/test/ui/closures/closure-return-type-mismatch.stderr
new file mode 100644
index 0000000..3a89d30
--- /dev/null
+++ b/src/test/ui/closures/closure-return-type-mismatch.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-return-type-mismatch.rs:7:9
+   |
+LL |         a
+   |         ^ expected `&str`, found `bool`
+   |
+note: return type inferred to be `&str` here
+  --> $DIR/closure-return-type-mismatch.rs:4:20
+   |
+LL |             return "test";
+   |                    ^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/closure-return-type-mismatch.rs:12:20
+   |
+LL |             return "hello"
+   |                    ^^^^^^^ expected `bool`, found `&str`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr
index 63eb0bd..bd2e316 100644
--- a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr
+++ b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr
@@ -12,7 +12,7 @@
    | |_____- `match` arms have incompatible types
    |
    = note: expected type `fn(i32, i32) -> i32 {add}`
-           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]`
+           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]`
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/closure_cap_coerce_many_fail.rs:18:16
@@ -28,7 +28,7 @@
    | |_____- `match` arms have incompatible types
    |
    = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
-           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]`
+           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
@@ -38,14 +38,14 @@
 LL |       let _ = match "+" {
    |  _____________-
 LL | |         "+" => |a, b| (a + b + cap) as i32,
-   | |                --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
+   | |                --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
 LL | |         "-" => |a, b| (a - b) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
+   = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
            found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
@@ -56,15 +56,15 @@
 LL |       let _ = match "+" {
    |  _____________-
 LL | |         "+" => |a, b| (a + b + cap) as i32,
-   | |                --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
+   | |                --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
 LL | |         "-" => |a, b| (a - b + cap) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
-           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]`
+   = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
+           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs
index af1e37b..909c33f 100644
--- a/src/test/ui/closures/issue-41366.rs
+++ b/src/test/ui/closures/issue-41366.rs
@@ -9,4 +9,5 @@
 fn main() {
     (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
     //~^ ERROR: type mismatch in closure arguments
+    //~| ERROR: size for values of type `<u32 as T<'_>>::V` cannot be known at compilation time
 }
diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr
index df0495c..200d411 100644
--- a/src/test/ui/closures/issue-41366.stderr
+++ b/src/test/ui/closures/issue-41366.stderr
@@ -9,6 +9,24 @@
    |
    = note: required for the cast to the object type `dyn for<'x> Fn(<u32 as T<'x>>::V)`
 
-error: aborting due to previous error
+error[E0277]: the size for values of type `<u32 as T<'_>>::V` cannot be known at compilation time
+  --> $DIR/issue-41366.rs:10:8
+   |
+LL |     (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+   |        ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<u32 as T<'_>>::V`
+   = help: unsized locals are gated as an unstable feature
+help: consider further restricting the associated type
+   |
+LL | fn main() where <u32 as T<'_>>::V: Sized {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     (&|&_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+   |        ^
 
-For more information about this error, try `rustc --explain E0631`.
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0631.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/closures/print/closure-print-generic-1.rs b/src/test/ui/closures/print/closure-print-generic-1.rs
new file mode 100644
index 0000000..504b4ad
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-1.rs
@@ -0,0 +1,23 @@
+fn to_fn_once<F: FnOnce()>(f: F) -> F {
+    f
+}
+
+fn f<T: std::fmt::Display>(y: T) {
+    struct Foo<U: std::fmt::Display> {
+        x: U,
+    };
+
+    let foo = Foo { x: "x" };
+
+    let c = to_fn_once(move || {
+        println!("{} {}", foo.x, y);
+    });
+
+    c();
+    c();
+    //~^ ERROR use of moved value
+}
+
+fn main() {
+    f("S");
+}
diff --git a/src/test/ui/closures/print/closure-print-generic-1.stderr b/src/test/ui/closures/print/closure-print-generic-1.stderr
new file mode 100644
index 0000000..43a12f6
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-1.stderr
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `c`
+  --> $DIR/closure-print-generic-1.rs:17:5
+   |
+LL |     let c = to_fn_once(move || {
+   |         - move occurs because `c` has type `[closure@$DIR/closure-print-generic-1.rs:12:24: 14:6]`, which does not implement the `Copy` trait
+...
+LL |     c();
+   |     --- `c` moved due to this call
+LL |     c();
+   |     ^ value used here after move
+   |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/closure-print-generic-1.rs:16:5
+   |
+LL |     c();
+   |     ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/print/closure-print-generic-2.rs b/src/test/ui/closures/print/closure-print-generic-2.rs
new file mode 100644
index 0000000..3f77fd2
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-2.rs
@@ -0,0 +1,13 @@
+mod mod1 {
+    pub fn f<T: std::fmt::Display>(t: T) {
+        let x = 20;
+
+        let c = || println!("{} {}", t, x);
+        let c1: () = c;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {
+    mod1::f(5i32);
+}
diff --git a/src/test/ui/closures/print/closure-print-generic-2.stderr b/src/test/ui/closures/print/closure-print-generic-2.stderr
new file mode 100644
index 0000000..f7cfbd2
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-2.stderr
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-print-generic-2.rs:6:22
+   |
+LL |         let c = || println!("{} {}", t, x);
+   |                 -------------------------- the found closure
+LL |         let c1: () = c;
+   |                 --   ^ expected `()`, found closure
+   |                 |
+   |                 expected due to this
+   |
+   = note: expected unit type `()`
+                found closure `[closure@$DIR/closure-print-generic-2.rs:5:17: 5:43]`
+help: use parentheses to call this closure
+   |
+LL |         let c1: () = c();
+   |                       ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs
new file mode 100644
index 0000000..07bf8fe
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs
@@ -0,0 +1,16 @@
+// compile-flags: -Ztrim-diagnostic-paths=off -Zverbose
+
+mod mod1 {
+    pub fn f<T: std::fmt::Display>(t: T)
+    {
+        let x = 20;
+
+        let c = || println!("{} {}", t, x);
+        let c1 : () = c;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {
+    mod1::f(5i32);
+}
diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
new file mode 100644
index 0000000..7fd9292
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-print-generic-trim-off-verbose-2.rs:9:23
+   |
+LL |         let c = || println!("{} {}", t, x);
+   |                 -------------------------- the found closure
+LL |         let c1 : () = c;
+   |                  --   ^ expected `()`, found closure
+   |                  |
+   |                  expected due to this
+   |
+   = note: expected unit type `()`
+                found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable)]`
+help: use parentheses to call this closure
+   |
+LL |         let c1 : () = c();
+   |                        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-1.rs b/src/test/ui/closures/print/closure-print-generic-verbose-1.rs
new file mode 100644
index 0000000..67d37f1
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-verbose-1.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Zverbose
+
+fn to_fn_once<F:FnOnce()>(f: F) -> F { f }
+
+fn f<T: std::fmt::Display>(y: T) {
+    struct Foo<U: std::fmt::Display> {
+        x: U
+    };
+
+    let foo =  Foo{ x: "x" };
+
+    let c = to_fn_once(move|| {
+        println!("{} {}", foo.x, y);
+    });
+
+    c();
+    c();
+    //~^ ERROR use of moved value
+}
+
+
+fn main() {
+    f("S");
+}
diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr
new file mode 100644
index 0000000..fdaf353
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `c`
+  --> $DIR/closure-print-generic-verbose-1.rs:17:5
+   |
+LL |     let c = to_fn_once(move|| {
+   |         - move occurs because `c` has type `[f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'_#10r str>, T)]`, which does not implement the `Copy` trait
+...
+LL |     c();
+   |     --- `c` moved due to this call
+LL |     c();
+   |     ^ value used here after move
+   |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/closure-print-generic-verbose-1.rs:16:5
+   |
+LL |     c();
+   |     ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.rs b/src/test/ui/closures/print/closure-print-generic-verbose-2.rs
new file mode 100644
index 0000000..f460fed
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.rs
@@ -0,0 +1,16 @@
+// compile-flags: -Zverbose
+
+mod mod1 {
+    pub fn f<T: std::fmt::Display>(t: T)
+    {
+        let x = 20;
+
+        let c = || println!("{} {}", t, x);
+        let c1 : () = c;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {
+    mod1::f(5i32);
+}
diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
new file mode 100644
index 0000000..680f6ff
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-print-generic-verbose-2.rs:9:23
+   |
+LL |         let c = || println!("{} {}", t, x);
+   |                 -------------------------- the found closure
+LL |         let c1 : () = c;
+   |                  --   ^ expected `()`, found closure
+   |                  |
+   |                  expected due to this
+   |
+   = note: expected unit type `()`
+                found closure `[f<T>::{closure#0} closure_substs=(unavailable)]`
+help: use parentheses to call this closure
+   |
+LL |         let c1 : () = c();
+   |                        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/print/closure-print-verbose.rs b/src/test/ui/closures/print/closure-print-verbose.rs
new file mode 100644
index 0000000..4b0438a
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-verbose.rs
@@ -0,0 +1,12 @@
+// compile-flags: -Zverbose
+
+// Same as closure-coerce-fn-1.rs
+
+// Ensure that capturing closures are never coerced to fns
+// Especially interesting as non-capturing closures can be.
+
+fn main() {
+    let mut a = 0u8;
+    let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/closures/print/closure-print-verbose.stderr b/src/test/ui/closures/print/closure-print-verbose.stderr
new file mode 100644
index 0000000..9e07137
--- /dev/null
+++ b/src/test/ui/closures/print/closure-print-verbose.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/closure-print-verbose.rs:10:29
+   |
+LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+   |              ------------   ^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found closure
+   |              |
+   |              expected due to this
+   |
+   = note: expected fn pointer `fn(u8) -> u8`
+                 found closure `[main::{closure#0} closure_substs=(unavailable)]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/cmse-nonsecure-entry/gate_test.rs b/src/test/ui/cmse-nonsecure-entry/gate_test.rs
new file mode 100644
index 0000000..02d5f20
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/gate_test.rs
@@ -0,0 +1,11 @@
+// gate-test-cmse_nonsecure_entry
+
+#[no_mangle]
+#[cmse_nonsecure_entry]
+//~^ ERROR [E0775]
+//~| ERROR [E0658]
+pub extern "C" fn entry_function(input: u32) -> u32 {
+    input + 6
+}
+
+fn main() {}
diff --git a/src/test/ui/cmse-nonsecure-entry/gate_test.stderr b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr
new file mode 100644
index 0000000..75a29b3
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr
@@ -0,0 +1,19 @@
+error[E0658]: the `#[cmse_nonsecure_entry]` attribute is an experimental feature
+  --> $DIR/gate_test.rs:4:1
+   |
+LL | #[cmse_nonsecure_entry]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #75835 <https://github.com/rust-lang/rust/issues/75835> for more information
+   = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable
+
+error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension
+  --> $DIR/gate_test.rs:4:1
+   |
+LL | #[cmse_nonsecure_entry]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0658, E0775.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs
new file mode 100644
index 0000000..a723eb7
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs
@@ -0,0 +1,11 @@
+// build-pass
+// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+// only-thumbv8m.main-none-eabi
+#![feature(cmse_nonsecure_entry)]
+#![no_std]
+
+#[no_mangle]
+#[cmse_nonsecure_entry]
+pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 {
+    a + b + c + d
+}
diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs
new file mode 100644
index 0000000..553d3a8
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs
@@ -0,0 +1,10 @@
+// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+// only-thumbv8m.main-none-eabi
+#![feature(cmse_nonsecure_entry)]
+#![no_std]
+
+#[no_mangle]
+#[cmse_nonsecure_entry]
+pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { //~ ERROR
+    a + b + c + d + e
+}
diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr
new file mode 100644
index 0000000..d9956ac
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr
@@ -0,0 +1,5 @@
+error: <unknown>:0:0: in function entry_function i32 (i32, i32, i32, i32, i32): secure entry function requires arguments on stack
+
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs
new file mode 100644
index 0000000..3783e27
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs
@@ -0,0 +1,10 @@
+// ignore-thumbv8m.main-none-eabi
+#![feature(cmse_nonsecure_entry)]
+
+#[no_mangle]
+#[cmse_nonsecure_entry] //~ ERROR [E0775]
+pub extern "C" fn entry_function(input: u32) -> u32 {
+    input + 6
+}
+
+fn main() {}
diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr
new file mode 100644
index 0000000..7e8862f
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr
@@ -0,0 +1,9 @@
+error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension
+  --> $DIR/trustzone-only.rs:5:1
+   |
+LL | #[cmse_nonsecure_entry]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0775`.
diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs
new file mode 100644
index 0000000..611c864
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs
@@ -0,0 +1,10 @@
+// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+// only-thumbv8m.main-none-eabi
+#![feature(cmse_nonsecure_entry)]
+#![no_std]
+
+#[no_mangle]
+#[cmse_nonsecure_entry]
+pub fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 { //~ ERROR [E0776]
+    a + b + c + d
+}
diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr
new file mode 100644
index 0000000..d6967a1
--- /dev/null
+++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr
@@ -0,0 +1,9 @@
+error[E0776]: `#[cmse_nonsecure_entry]` functions require C ABI
+  --> $DIR/wrong-abi.rs:7:1
+   |
+LL | #[cmse_nonsecure_entry]
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0776`.
diff --git a/src/test/ui/coherence/coherence-all-remote.stderr b/src/test/ui/coherence/coherence-all-remote.stderr
index 6ecfb2c..7eca417 100644
--- a/src/test/ui/coherence/coherence-all-remote.stderr
+++ b/src/test/ui/coherence/coherence-all-remote.stderr
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<T> for isize { }
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to previous error
diff --git a/src/test/ui/coherence/coherence-bigint-param.stderr b/src/test/ui/coherence/coherence-bigint-param.stderr
index d431c5f..e8d74c9 100644
--- a/src/test/ui/coherence/coherence-bigint-param.stderr
+++ b/src/test/ui/coherence/coherence-bigint-param.stderr
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<BigInt> for T { }
    |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`BigInt`)
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
 
 error: aborting due to previous error
diff --git a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr
index 5381053..827d26a 100644
--- a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr
+++ b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr
@@ -13,7 +13,7 @@
 LL | impl<A> Foo for A {
    |      ^ type parameter `A` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr
index cd18a01..a2b779e 100644
--- a/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr
+++ b/src/test/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr
@@ -1,14 +1,17 @@
 error[E0038]: the trait `NotObjectSafe` cannot be made into an object
   --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:24
    |
-LL | trait NotObjectSafe { fn eq(&self, other: Self); }
-   |       -------------                       ---- ...because method `eq` references the `Self` type in this parameter
-   |       |
-   |       this trait cannot be made into an object...
 LL | impl NotObjectSafe for dyn NotObjectSafe { }
-   |                        ^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
+   |                        ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object
    |
    = help: consider moving `eq` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:6:43
+   |
+LL | trait NotObjectSafe { fn eq(&self, other: Self); }
+   |       -------------                       ^^^^ ...because method `eq` references the `Self` type in this parameter
+   |       |
+   |       this trait cannot be made into an object...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr
index 7e14048..f3edf1c 100644
--- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr
+++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0391]: cycle detected when building specialization graph of trait `Trait`
   --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1
diff --git a/src/test/ui/coherence/coherence-lone-type-parameter.stderr b/src/test/ui/coherence/coherence-lone-type-parameter.stderr
index 2c3b4fc..ef5b088 100644
--- a/src/test/ui/coherence/coherence-lone-type-parameter.stderr
+++ b/src/test/ui/coherence/coherence-lone-type-parameter.stderr
@@ -4,7 +4,7 @@
 LL | impl<T> Remote for T { }
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to previous error
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign-for-fundamental\133t\135.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign-for-fundamental\133t\135.stderr"
index 8a951d4..249a5c4 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign-for-fundamental\133t\135.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign-for-fundamental\133t\135.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote for Box<T> {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to previous error
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-fundamental\133t\135.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-fundamental\133t\135.stderr"
index c575924..95a20cc 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-fundamental\133t\135.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-fundamental\133t\135.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<u32> for Box<T> {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
@@ -13,7 +13,7 @@
 LL | impl<'a, T> Remote1<u32> for &'a T {
    |          ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-t.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-t.stderr"
index e8663fd..aed1847 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-t.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133foreign\135-for-t.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<u32> for T {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to previous error
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-foreign.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-foreign.stderr"
index 639bee2..73b1e2c 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-foreign.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-foreign.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<Box<T>> for u32 {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
@@ -13,7 +13,7 @@
 LL | impl<'a, T> Remote1<&'a T> for u32 {
    |          ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-fundamental\133t\135.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-fundamental\133t\135.stderr"
index 0b6c81b..5f89a7aa 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-fundamental\133t\135.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-fundamental\133t\135.stderr"
@@ -4,7 +4,7 @@
 LL | impl<'a, T> Remote1<Box<T>> for &'a T {
    |          ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
@@ -13,7 +13,7 @@
 LL | impl<'a, T> Remote1<&'a T> for Box<T> {
    |          ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-t.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-t.stderr"
index fe40490..45559d8 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-t.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135\135-for-t.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<Box<T>> for T {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
@@ -13,7 +13,7 @@
 LL | impl<'a, T> Remote1<&'a T> for T {
    |          ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135_local\135-for-foreign.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135_local\135-for-foreign.stderr"
index 1eaef59..f94f04c 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135_local\135-for-foreign.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133fundamental\133t\135_local\135-for-foreign.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote2<Box<T>, Local> for u32 {
    |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
 
 error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
@@ -13,7 +13,7 @@
 LL | impl<'a, T> Remote2<&'a T, Local> for u32 {
    |          ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
 
 error: aborting due to 2 previous errors
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-fundamental\133t\135.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-fundamental\133t\135.stderr"
index 4d39186..e68f2fe 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-fundamental\133t\135.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-fundamental\133t\135.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<Local> for Box<T> {
    |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
 
 error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
@@ -13,7 +13,7 @@
 LL | impl<T> Remote1<Local> for &T {
    |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
 
 error: aborting due to 2 previous errors
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-t.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-t.stderr"
index d74be4c..d97e85d 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-t.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133local\135-for-t.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<Local> for T {
    |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
 
 error: aborting due to previous error
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-foreign.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-foreign.stderr"
index b26feb4..44e3b7e 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-foreign.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-foreign.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<T> for u32 {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to previous error
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-fundamental.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-fundamental.stderr"
index 5e8cc55..80fb5db 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-fundamental.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-fundamental.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<T> for Box<T> {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error[E0210]: type parameter `B` must be used as the type parameter for some local type (e.g., `MyStruct<B>`)
@@ -13,7 +13,7 @@
 LL | impl<'a, A, B> Remote1<A> for &'a B {
    |             ^ type parameter `B` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git "a/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-t.stderr" "b/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-t.stderr"
index d3226d3..ff72969 100644
--- "a/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-t.stderr"
+++ "b/src/test/ui/coherence/impl\133t\135-foreign\133t\135-for-t.stderr"
@@ -4,7 +4,7 @@
 LL | impl<T> Remote1<T> for T {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to previous error
diff --git a/src/test/ui/conservative_impl_trait.stderr b/src/test/ui/conservative_impl_trait.stderr
index 87058c3..63a4df2 100644
--- a/src/test/ui/conservative_impl_trait.stderr
+++ b/src/test/ui/conservative_impl_trait.stderr
@@ -5,7 +5,6 @@
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `()`
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
index 809514e..cfaacf7 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/array-size-in-generic-struct-param.rs:9:48
    |
 LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
-   |                                                ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                                ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/array-size-in-generic-struct-param.rs:20:15
    |
 LL |     arr: [u8; CFG.arr_size],
-   |               ^^^ non-trivial anonymous constants must not depend on the parameter `CFG`
+   |               ^^^ cannot perform const operation using `CFG`
    |
-   = help: it is currently only allowed to use either `CFG` or `{ CFG }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `CFG`
 
 error: `Config` is forbidden as the type of a const generic parameter
   --> $DIR/array-size-in-generic-struct-param.rs:18:21
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
index 8bd3b78..768180d 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
@@ -8,7 +8,7 @@
 #[allow(dead_code)]
 struct ArithArrayLen<const N: usize>([u32; 0 + N]);
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 
 #[derive(PartialEq, Eq)]
 struct Config {
@@ -19,7 +19,7 @@
     //[min]~^ ERROR `Config` is forbidden
     arr: [u8; CFG.arr_size],
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non trivial
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 const C: Config = Config { arr_size: 5 };
diff --git a/src/test/ui/const-generics/const-argument-if-length.full.stderr b/src/test/ui/const-generics/const-argument-if-length.full.stderr
new file mode 100644
index 0000000..9b1c1be
--- /dev/null
+++ b/src/test/ui/const-generics/const-argument-if-length.full.stderr
@@ -0,0 +1,42 @@
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/const-argument-if-length.rs:8:28
+   |
+LL | pub const fn is_zst<T: ?Sized>() -> usize {
+   |                     - this type parameter needs to be `Sized`
+LL |     if std::mem::size_of::<T>() == 0 {
+   |                            ^ doesn't have a size known at compile-time
+   | 
+  ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |
+LL | pub const fn size_of<T>() -> usize {
+   |                      - required by this bound in `std::mem::size_of`
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/const-argument-if-length.rs:19:15
+   |
+LL |     pad: [u8; is_zst::<T>()],
+   |               ^^^^^^^^^^^^^ referenced constant has errors
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/const-argument-if-length.rs:17:12
+   |
+LL | pub struct AtLeastByte<T: ?Sized> {
+   |                        - this type parameter needs to be `Sized`
+LL |     value: T,
+   |            ^ doesn't have a size known at compile-time
+   |
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     value: &T,
+   |            ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     value: Box<T>,
+   |            ^^^^ ^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-generics/const-argument-if-length.min.stderr b/src/test/ui/const-generics/const-argument-if-length.min.stderr
new file mode 100644
index 0000000..bce701a
--- /dev/null
+++ b/src/test/ui/const-generics/const-argument-if-length.min.stderr
@@ -0,0 +1,30 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/const-argument-if-length.rs:19:24
+   |
+LL |     pad: [u8; is_zst::<T>()],
+   |                        ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/const-argument-if-length.rs:17:12
+   |
+LL | pub struct AtLeastByte<T: ?Sized> {
+   |                        - this type parameter needs to be `Sized`
+LL |     value: T,
+   |            ^ doesn't have a size known at compile-time
+   |
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     value: &T,
+   |            ^
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     value: Box<T>,
+   |            ^^^^ ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/const-argument-if-length.rs b/src/test/ui/const-generics/const-argument-if-length.rs
new file mode 100644
index 0000000..a8bffd1
--- /dev/null
+++ b/src/test/ui/const-generics/const-argument-if-length.rs
@@ -0,0 +1,24 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+pub const fn is_zst<T: ?Sized>() -> usize {
+    if std::mem::size_of::<T>() == 0 {
+        //[full]~^ ERROR the size for values of type `T` cannot be known at compilation time
+        1
+    } else {
+        0
+    }
+}
+
+pub struct AtLeastByte<T: ?Sized> {
+    value: T,
+    //~^ ERROR the size for values of type `T` cannot be known at compilation time
+    pad: [u8; is_zst::<T>()],
+    //[min]~^ ERROR generic parameters may not be used in const operations
+    //[full]~^^ ERROR evaluation of constant value failed
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs
index 52b89cf..e3a4d9a 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs
@@ -5,10 +5,10 @@
 
 fn user<T>() {
     let _ = const_evaluatable_lib::test1::<T>();
-    //~^ ERROR constant expression depends
-    //~| ERROR constant expression depends
-    //~| ERROR constant expression depends
-    //~| ERROR constant expression depends
+    //~^ ERROR unconstrained generic constant
+    //~| ERROR unconstrained generic constant
+    //~| ERROR unconstrained generic constant
+    //~| ERROR unconstrained generic constant
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
index 4af6811..8a298b4 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
@@ -1,54 +1,50 @@
-error: constant expression depends on a generic parameter
+error: unconstrained generic constant
   --> $DIR/cross_crate_predicate.rs:7:13
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
-  ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
+   |
+help: consider adding a `where` bound for this expression
+  --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
    |
 LL |     [u8; std::mem::size_of::<T>() - 1]: Sized,
-   |          ---------------------------- required by this bound in `test1`
-   |
-   = note: this may fail depending on what value the parameter takes
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: constant expression depends on a generic parameter
+error: unconstrained generic constant
   --> $DIR/cross_crate_predicate.rs:7:13
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
-  ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
+   |
+help: consider adding a `where` bound for this expression
+  --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
    |
 LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
-   |                           ---------------------------- required by this bound in `test1`
-   |
-   = note: this may fail depending on what value the parameter takes
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: constant expression depends on a generic parameter
+error: unconstrained generic constant
   --> $DIR/cross_crate_predicate.rs:7:13
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
-  ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:10
+   |
+help: consider adding a `where` bound for this expression
+  --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10
    |
 LL |     [u8; std::mem::size_of::<T>() - 1]: Sized,
-   |          ---------------------------- required by this bound in `test1`
-   |
-   = note: this may fail depending on what value the parameter takes
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: constant expression depends on a generic parameter
+error: unconstrained generic constant
   --> $DIR/cross_crate_predicate.rs:7:13
    |
 LL |     let _ = const_evaluatable_lib::test1::<T>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   | 
-  ::: $DIR/auxiliary/const_evaluatable_lib.rs:4:27
+   |
+help: consider adding a `where` bound for this expression
+  --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27
    |
 LL | pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
-   |                           ---------------------------- required by this bound in `test1`
-   |
-   = note: this may fail depending on what value the parameter takes
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
index 269710d..359c2d2 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
-   |                                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
index af30901..9746ada 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
@@ -4,7 +4,7 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 type Arr<const N: usize> = [u8; N - 1];
-//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
     //[full]~^ ERROR constant expression depends
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr
index a5acfec..25af18e 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr
@@ -2,7 +2,7 @@
   --> $DIR/from-sig-fail.rs:4:35
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] {
-   |                                   ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow
+   |                                   ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs b/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs
new file mode 100644
index 0000000..cad06ea
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+use std::{mem, ptr};
+
+fn split_first<T, const N: usize>(arr: [T; N]) -> (T, [T; N - 1])
+where
+    [T; N - 1]: Sized,
+{
+    let arr = mem::ManuallyDrop::new(arr);
+    unsafe {
+        let head = ptr::read(&arr[0]);
+        let tail = ptr::read(&arr[1..] as *const [T] as *const [T; N - 1]);
+        (head, tail)
+    }
+}
+
+fn main() {
+    let arr = [0, 1, 2, 3, 4];
+    let (head, tail) = split_first(arr);
+    assert_eq!(head, 0);
+    assert_eq!(tail, [1, 2, 3, 4]);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
index 3cac604..4648526 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/simple.rs:8:53
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
-   |                                                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                                     ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/simple.rs:8:35
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
-   |                                   ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                   ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
index 104cab8..f95d6d2 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
@@ -2,7 +2,7 @@
   --> $DIR/simple_fail.rs:7:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
-   |                                 ^^^^^ attempt to compute `0_usize - 1_usize` which would overflow
+   |                                 ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
index 042710f..981d993 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/simple_fail.rs:7:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
-   |                                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
index b15e0ff..5e2c0809 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
@@ -5,7 +5,7 @@
 #![allow(incomplete_features)]
 
 type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
-//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized {
     todo!()
diff --git a/src/test/ui/const-generics/defaults/wrong-order.full.stderr b/src/test/ui/const-generics/defaults/wrong-order.full.stderr
index c51028d..99f4630 100644
--- a/src/test/ui/const-generics/defaults/wrong-order.full.stderr
+++ b/src/test/ui/const-generics/defaults/wrong-order.full.stderr
@@ -14,6 +14,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.full.stderr b/src/test/ui/const-generics/generic-function-call-in-array-length.full.stderr
new file mode 100644
index 0000000..43b42d8
--- /dev/null
+++ b/src/test/ui/const-generics/generic-function-call-in-array-length.full.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/generic-function-call-in-array-length.rs:9:29
+   |
+LL | fn bar<const N: usize>() -> [u32; foo(N)] {
+   |                             ^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
new file mode 100644
index 0000000..8444901
--- /dev/null
+++ b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
@@ -0,0 +1,18 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/generic-function-call-in-array-length.rs:9:39
+   |
+LL | fn bar<const N: usize>() -> [u32; foo(N)] {
+   |                                       ^ cannot perform const operation using `N`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+
+error: generic parameters may not be used in const operations
+  --> $DIR/generic-function-call-in-array-length.rs:12:13
+   |
+LL |     [0; foo(N)]
+   |             ^ cannot perform const operation using `N`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.rs b/src/test/ui/const-generics/generic-function-call-in-array-length.rs
new file mode 100644
index 0000000..c838070
--- /dev/null
+++ b/src/test/ui/const-generics/generic-function-call-in-array-length.rs
@@ -0,0 +1,16 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+const fn foo(n: usize) -> usize { n * 2 }
+
+fn bar<const N: usize>() -> [u32; foo(N)] {
+    //[min]~^ ERROR generic parameters may not be used in const operations
+    //[full]~^^ ERROR constant expression depends on a generic parameter
+    [0; foo(N)]
+    //[min]~^ ERROR generic parameters may not be used in const operations
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.full.stderr b/src/test/ui/const-generics/generic-sum-in-array-length.full.stderr
new file mode 100644
index 0000000..d311e1c
--- /dev/null
+++ b/src/test/ui/const-generics/generic-sum-in-array-length.full.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/generic-sum-in-array-length.rs:7:45
+   |
+LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
+   |                                             ^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
new file mode 100644
index 0000000..d3f7143
--- /dev/null
+++ b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
@@ -0,0 +1,18 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/generic-sum-in-array-length.rs:7:53
+   |
+LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
+   |                                                     ^ cannot perform const operation using `A`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `A`
+
+error: generic parameters may not be used in const operations
+  --> $DIR/generic-sum-in-array-length.rs:7:57
+   |
+LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
+   |                                                         ^ cannot perform const operation using `B`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `B`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.rs b/src/test/ui/const-generics/generic-sum-in-array-length.rs
new file mode 100644
index 0000000..84ddfe0
--- /dev/null
+++ b/src/test/ui/const-generics/generic-sum-in-array-length.rs
@@ -0,0 +1,12 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
+//[min]~^ ERROR generic parameters may not be used in const operations
+//[min]~| ERROR generic parameters may not be used in const operations
+//[full]~^^^ ERROR constant expression depends on a generic parameter
+
+fn main() {}
diff --git a/src/test/ui/const-generics/impl-trait-with-const-arguments.full.stderr b/src/test/ui/const-generics/impl-trait-with-const-arguments.full.stderr
new file mode 100644
index 0000000..a587cb6
--- /dev/null
+++ b/src/test/ui/const-generics/impl-trait-with-const-arguments.full.stderr
@@ -0,0 +1,8 @@
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
+  --> $DIR/impl-trait-with-const-arguments.rs:24:20
+   |
+LL |     assert_eq!(f::<4usize>(Usizable), 20usize);
+   |                    ^^^^^^ explicit generic argument not allowed
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/impl-trait-with-const-arguments.min.stderr b/src/test/ui/const-generics/impl-trait-with-const-arguments.min.stderr
new file mode 100644
index 0000000..a587cb6
--- /dev/null
+++ b/src/test/ui/const-generics/impl-trait-with-const-arguments.min.stderr
@@ -0,0 +1,8 @@
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
+  --> $DIR/impl-trait-with-const-arguments.rs:24:20
+   |
+LL |     assert_eq!(f::<4usize>(Usizable), 20usize);
+   |                    ^^^^^^ explicit generic argument not allowed
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/impl-trait-with-const-arguments.rs b/src/test/ui/const-generics/impl-trait-with-const-arguments.rs
new file mode 100644
index 0000000..a4c7579
--- /dev/null
+++ b/src/test/ui/const-generics/impl-trait-with-const-arguments.rs
@@ -0,0 +1,26 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+trait Usizer {
+    fn m(self) -> usize;
+}
+
+fn f<const N: usize>(u: impl Usizer) -> usize {
+    N + u.m()
+}
+
+struct Usizable;
+
+impl Usizer for Usizable {
+    fn m(self) -> usize {
+        16
+    }
+}
+
+fn main() {
+    assert_eq!(f::<4usize>(Usizable), 20usize);
+//~^ ERROR cannot provide explicit generic arguments when `impl Trait` is used in argument position
+}
diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.full.stderr b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.full.stderr
new file mode 100644
index 0000000..c09d16d
--- /dev/null
+++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.full.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:15:8
+   |
+LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
new file mode 100644
index 0000000..20a8d9f
--- /dev/null
+++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
@@ -0,0 +1,19 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44
+   |
+LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
+   |                                            ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+
+error: `&'static str` is forbidden as the type of a const generic parameter
+  --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
+   |
+LL | trait Trait<const S: &'static str> {}
+   |                      ^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs
new file mode 100644
index 0000000..8971c00
--- /dev/null
+++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs
@@ -0,0 +1,22 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+#![feature(core_intrinsics)]
+#![feature(const_type_name)]
+
+trait Trait<const S: &'static str> {}
+//[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter
+
+struct Bug<T>
+where
+    T: Trait<{std::intrinsics::type_name::<T>()}>
+    //[min]~^ ERROR generic parameters may not be used in const operations
+    //[full]~^^ ERROR constant expression depends on a generic parameter
+{
+    t: T
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
index a1b1a09..526807f 100644
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61522-array-len-succ.rs:7:45
    |
 LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
-   |                                             ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT`
+   |                                             ^^^^^ cannot perform const operation using `COUNT`
    |
-   = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61522-array-len-succ.rs:12:30
    |
 LL |     fn inner(&self) -> &[u8; COUNT + 1] {
-   |                              ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT`
+   |                              ^^^^^ cannot perform const operation using `COUNT`
    |
-   = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.rs b/src/test/ui/const-generics/issue-61522-array-len-succ.rs
index 81443b9..8c0a3a0 100644
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.rs
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.rs
@@ -6,12 +6,12 @@
 
 pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used
+//[min]~^^ ERROR generic parameters may not be used
 
 impl<const COUNT: usize> MyArray<COUNT> {
     fn inner(&self) -> &[u8; COUNT + 1] {
         //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters must not be used
+        //[min]~^^ ERROR generic parameters may not be used
         &self.0
     }
 }
diff --git a/src/test/ui/const-generics/issue-67375.full.stderr b/src/test/ui/const-generics/issue-67375.full.stderr
new file mode 100644
index 0000000..e15d65f
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67375.full.stderr
@@ -0,0 +1,21 @@
+warning: cannot use constants which depend on generic parameters in types
+  --> $DIR/issue-67375.rs:9:12
+   |
+LL |     inner: [(); { [|_: &T| {}; 0].len() }],
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(const_evaluatable_unchecked)]` on by default
+   = 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 #76200 <https://github.com/rust-lang/rust/issues/76200>
+
+error[E0392]: parameter `T` is never used
+  --> $DIR/issue-67375.rs:7:12
+   |
+LL | struct Bug<T> {
+   |            ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/issue-67375.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr
new file mode 100644
index 0000000..3c344ed
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67375.min.stderr
@@ -0,0 +1,19 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-67375.rs:9:25
+   |
+LL |     inner: [(); { [|_: &T| {}; 0].len() }],
+   |                         ^ cannot perform const operation using `T`
+   |
+   = note: type parameters may not be used in const expressions
+
+error[E0392]: parameter `T` is never used
+  --> $DIR/issue-67375.rs:7:12
+   |
+LL | struct Bug<T> {
+   |            ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/issue-67375.rs b/src/test/ui/const-generics/issue-67375.rs
new file mode 100644
index 0000000..ecc76bc
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67375.rs
@@ -0,0 +1,15 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct Bug<T> {
+    //~^ ERROR parameter `T` is never used
+    inner: [(); { [|_: &T| {}; 0].len() }],
+    //[min]~^ ERROR generic parameters may not be used in const operations
+    //[full]~^^ WARN cannot use constants which depend on generic parameters in types
+    //[full]~^^^ WARN this was previously accepted by the compiler
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issue-67945-1.full.stderr b/src/test/ui/const-generics/issue-67945-1.full.stderr
new file mode 100644
index 0000000..e79c4f5
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-1.full.stderr
@@ -0,0 +1,26 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-67945-1.rs:14:20
+   |
+LL | struct Bug<S> {
+   |            - this type parameter
+...
+LL |         let x: S = MaybeUninit::uninit();
+   |                -   ^^^^^^^^^^^^^^^^^^^^^ expected type parameter `S`, found union `MaybeUninit`
+   |                |
+   |                expected due to this
+   |
+   = note: expected type parameter `S`
+                       found union `MaybeUninit<_>`
+
+error[E0392]: parameter `S` is never used
+  --> $DIR/issue-67945-1.rs:11:12
+   |
+LL | struct Bug<S> {
+   |            ^ unused parameter
+   |
+   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0392.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr
new file mode 100644
index 0000000..804236c
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-1.min.stderr
@@ -0,0 +1,27 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-67945-1.rs:14:16
+   |
+LL |         let x: S = MaybeUninit::uninit();
+   |                ^ cannot perform const operation using `S`
+   |
+   = note: type parameters may not be used in const expressions
+
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-67945-1.rs:17:45
+   |
+LL |         let b = &*(&x as *const _ as *const S);
+   |                                             ^ cannot perform const operation using `S`
+   |
+   = note: type parameters may not be used in const expressions
+
+error[E0392]: parameter `S` is never used
+  --> $DIR/issue-67945-1.rs:11:12
+   |
+LL | struct Bug<S> {
+   |            ^ unused parameter
+   |
+   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/issue-67945-1.rs b/src/test/ui/const-generics/issue-67945-1.rs
new file mode 100644
index 0000000..6771603
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-1.rs
@@ -0,0 +1,23 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+use std::marker::PhantomData;
+
+use std::mem::{self, MaybeUninit};
+
+struct Bug<S> {
+    //~^ ERROR parameter `S` is never used
+    A: [(); {
+        let x: S = MaybeUninit::uninit();
+        //[min]~^ ERROR generic parameters may not be used in const operations
+        //[full]~^^ ERROR mismatched types
+        let b = &*(&x as *const _ as *const S);
+        //[min]~^ ERROR generic parameters may not be used in const operations
+        0
+    }],
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issue-67945-2.full.stderr b/src/test/ui/const-generics/issue-67945-2.full.stderr
new file mode 100644
index 0000000..2f54b80
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-2.full.stderr
@@ -0,0 +1,26 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-67945-2.rs:12:20
+   |
+LL | struct Bug<S> {
+   |            - this type parameter
+...
+LL |         let x: S = MaybeUninit::uninit();
+   |                -   ^^^^^^^^^^^^^^^^^^^^^ expected type parameter `S`, found union `MaybeUninit`
+   |                |
+   |                expected due to this
+   |
+   = note: expected type parameter `S`
+                       found union `MaybeUninit<_>`
+
+error[E0392]: parameter `S` is never used
+  --> $DIR/issue-67945-2.rs:9:12
+   |
+LL | struct Bug<S> {
+   |            ^ unused parameter
+   |
+   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0392.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr
new file mode 100644
index 0000000..2de942c
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-2.min.stderr
@@ -0,0 +1,27 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-67945-2.rs:12:16
+   |
+LL |         let x: S = MaybeUninit::uninit();
+   |                ^ cannot perform const operation using `S`
+   |
+   = note: type parameters may not be used in const expressions
+
+error: generic parameters may not be used in const operations
+  --> $DIR/issue-67945-2.rs:15:45
+   |
+LL |         let b = &*(&x as *const _ as *const S);
+   |                                             ^ cannot perform const operation using `S`
+   |
+   = note: type parameters may not be used in const expressions
+
+error[E0392]: parameter `S` is never used
+  --> $DIR/issue-67945-2.rs:9:12
+   |
+LL | struct Bug<S> {
+   |            ^ unused parameter
+   |
+   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/issue-67945-2.rs b/src/test/ui/const-generics/issue-67945-2.rs
new file mode 100644
index 0000000..72dbb67
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-2.rs
@@ -0,0 +1,21 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+use std::mem::MaybeUninit;
+
+struct Bug<S> {
+    //~^ ERROR parameter `S` is never used
+    A: [(); {
+        let x: S = MaybeUninit::uninit();
+        //[min]~^ ERROR generic parameters may not be used in const operations
+        //[full]~^^ ERROR mismatched types
+        let b = &*(&x as *const _ as *const S);
+        //[min]~^ ERROR generic parameters may not be used in const operations
+        0
+    }],
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issue-67945-3.full.stderr b/src/test/ui/const-generics/issue-67945-3.full.stderr
new file mode 100644
index 0000000..c33b885
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-3.full.stderr
@@ -0,0 +1,16 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-67945-3.rs:8:8
+   |
+LL |       A: [(); {
+   |  ________^
+LL | |
+LL | |         let x: Option<Box<Self>> = None;
+LL | |
+LL | |         0
+LL | |     }],
+   | |______^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issue-67945-3.min.stderr b/src/test/ui/const-generics/issue-67945-3.min.stderr
new file mode 100644
index 0000000..9c6e101
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-3.min.stderr
@@ -0,0 +1,8 @@
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/issue-67945-3.rs:10:27
+   |
+LL |         let x: Option<Box<Self>> = None;
+   |                           ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issue-67945-3.rs b/src/test/ui/const-generics/issue-67945-3.rs
new file mode 100644
index 0000000..bca0791
--- /dev/null
+++ b/src/test/ui/const-generics/issue-67945-3.rs
@@ -0,0 +1,17 @@
+// revisions: full min
+
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct Bug<S: ?Sized> {
+    A: [(); {
+        //[full]~^ ERROR constant expression depends on a generic parameter
+        let x: Option<Box<Self>> = None;
+        //[min]~^ ERROR generic `Self` types are currently not permitted in anonymous constants
+        0
+    }],
+    B: S
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issue-74906.rs b/src/test/ui/const-generics/issue-74906.rs
new file mode 100644
index 0000000..9162d11
--- /dev/null
+++ b/src/test/ui/const-generics/issue-74906.rs
@@ -0,0 +1,25 @@
+// edition:2018
+// check-pass
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+const SIZE: usize = 16;
+
+struct Bar<const H: usize> {}
+
+struct Foo<const H: usize> {}
+
+impl<const H: usize> Foo<H> {
+    async fn biz(_: &[[u8; SIZE]]) -> Vec<()> {
+        vec![]
+    }
+
+    pub async fn baz(&self) -> Bar<H> {
+        Self::biz(&vec![]).await;
+        Bar {}
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/const-generics/issues/issue-56445.full.stderr b/src/test/ui/const-generics/issues/issue-56445.full.stderr
index d853ec5..50e9141 100644
--- a/src/test/ui/const-generics/issues/issue-56445.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-56445.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0771]: use of non-static lifetime `'a` in const generic
   --> $DIR/issue-56445.rs:9:26
diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr
index c03b725..cc014ea 100644
--- a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr
index f18728e..3a9f819 100644
--- a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr
index ef6e600..883ebbe 100644
--- a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/issue-61336-2.rs:10:5
diff --git a/src/test/ui/const-generics/issues/issue-61336.full.stderr b/src/test/ui/const-generics/issues/issue-61336.full.stderr
index bdfdffd..3863da8 100644
--- a/src/test/ui/const-generics/issues/issue-61336.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/issue-61336.rs:10:5
diff --git a/src/test/ui/const-generics/issues/issue-61422.full.stderr b/src/test/ui/const-generics/issues/issue-61422.full.stderr
index ac6c378..294378a 100644
--- a/src/test/ui/const-generics/issues/issue-61422.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-61422.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-61432.full.stderr b/src/test/ui/const-generics/issues/issue-61432.full.stderr
index 82b36de..eec1b20 100644
--- a/src/test/ui/const-generics/issues/issue-61432.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-61432.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-61747.full.stderr b/src/test/ui/const-generics/issues/issue-61747.full.stderr
index 3ccce56..3a266c8 100644
--- a/src/test/ui/const-generics/issues/issue-61747.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-61747.full.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: constant expression depends on a generic parameter
   --> $DIR/issue-61747.rs:8:23
diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr
index 2061b6c..b176f9d 100644
--- a/src/test/ui/const-generics/issues/issue-61747.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-61747.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61747.rs:8:30
    |
 LL |     fn successor() -> Const<{C + 1}> {
-   |                              ^ non-trivial anonymous constants must not depend on the parameter `C`
+   |                              ^ cannot perform const operation using `C`
    |
-   = help: it is currently only allowed to use either `C` or `{ C }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `C`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs
index 4e5cde1..3a4dd1cd 100644
--- a/src/test/ui/const-generics/issues/issue-61747.rs
+++ b/src/test/ui/const-generics/issues/issue-61747.rs
@@ -7,7 +7,7 @@
 impl<const C: usize> Const<{C}> {
     fn successor() -> Const<{C + 1}> {
         //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters must not be used
+        //[min]~^^ ERROR generic parameters may not be used
         Const
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr
index e5715ec..9e31466 100644
--- a/src/test/ui/const-generics/issues/issue-61935.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61935.rs:10:23
    |
 LL |         Self:FooImpl<{N==0}>
-   |                       ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                       ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs
index 64257da..9fa0232 100644
--- a/src/test/ui/const-generics/issues/issue-61935.rs
+++ b/src/test/ui/const-generics/issues/issue-61935.rs
@@ -9,7 +9,7 @@
     where
         Self:FooImpl<{N==0}>
 //[full]~^ERROR constant expression depends on a generic parameter
-//[min]~^^ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^^ERROR generic parameters may not be used in const operations
 {}
 
 trait FooImpl<const IS_ZERO: bool>{}
diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr
index 943b689..3bd127e 100644
--- a/src/test/ui/const-generics/issues/issue-62220.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-62220.rs:8:59
    |
 LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
-   |                                                           ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                                           ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs
index acb13ad..2017473 100644
--- a/src/test/ui/const-generics/issues/issue-62220.rs
+++ b/src/test/ui/const-generics/issues/issue-62220.rs
@@ -6,7 +6,7 @@
 pub struct Vector<T, const N: usize>([T; N]);
 
 pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
-//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 impl<T, const N: usize> Vector<T, { N }> {
     /// Drop the last component and return the vector with one fewer dimension.
diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr
index 335f0ea..c73f62a 100644
--- a/src/test/ui/const-generics/issues/issue-62456.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-62456.rs:7:20
    |
 LL |     let _ = [0u64; N + 1];
-   |                    ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                    ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs
index c96868c..cbb2a11 100644
--- a/src/test/ui/const-generics/issues/issue-62456.rs
+++ b/src/test/ui/const-generics/issues/issue-62456.rs
@@ -6,7 +6,7 @@
 fn foo<const N: usize>() {
     let _ = [0u64; N + 1];
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr
index 07822f86f..8b02fd1 100644
--- a/src/test/ui/const-generics/issues/issue-64494.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-64494.rs:16:38
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
-   |                                      ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                      ^^^^^^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-64494.rs:19:38
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
-   |                                      ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                      ^^^^^^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0119]: conflicting implementations of trait `MyTrait`:
   --> $DIR/issue-64494.rs:19:1
diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs
index 3b598a4..014742b 100644
--- a/src/test/ui/const-generics/issues/issue-64494.rs
+++ b/src/test/ui/const-generics/issues/issue-64494.rs
@@ -15,10 +15,10 @@
 
 impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 //[min]~| ERROR conflicting implementations of trait `MyTrait`
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr
index 86709c3..282f72b 100644
--- a/src/test/ui/const-generics/issues/issue-66205.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-66205.rs:8:14
    |
 LL |     fact::<{ N - 1 }>();
-   |              ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |              ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs
index e115eff..4e37c24 100644
--- a/src/test/ui/const-generics/issues/issue-66205.rs
+++ b/src/test/ui/const-generics/issues/issue-66205.rs
@@ -7,7 +7,7 @@
 fn fact<const N: usize>() {
     fact::<{ N - 1 }>();
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr
index 68f1733..35d97c4 100644
--- a/src/test/ui/const-generics/issues/issue-67739.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-67739.rs:12:30
    |
 LL |         [0u8; mem::size_of::<Self::Associated>()];
-   |                              ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |                              ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs
index 72bf3ee..21d13de 100644
--- a/src/test/ui/const-generics/issues/issue-67739.rs
+++ b/src/test/ui/const-generics/issues/issue-67739.rs
@@ -11,7 +11,7 @@
     fn associated_size(&self) -> usize {
         [0u8; mem::size_of::<Self::Associated>()];
         //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+        //[min]~^^ ERROR generic parameters may not be used in const operations
         0
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr
index 8d34bdc..b900a0d 100644
--- a/src/test/ui/const-generics/issues/issue-68366.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-68366.rs:12:37
    |
 LL | impl <const N: usize> Collatz<{Some(N)}> {}
-   |                                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                     ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
   --> $DIR/issue-68366.rs:12:13
diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs
index 819fcaf..474cdb7 100644
--- a/src/test/ui/const-generics/issues/issue-68366.rs
+++ b/src/test/ui/const-generics/issues/issue-68366.rs
@@ -11,7 +11,7 @@
 
 impl <const N: usize> Collatz<{Some(N)}> {}
 //~^ ERROR the const parameter
-//[min]~^^ generic parameters must not be used inside of non trivial constant values
+//[min]~^^ generic parameters may not be used in const operations
 
 struct Foo;
 
diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr
index 5b2137b..7828d85 100644
--- a/src/test/ui/const-generics/issues/issue-68977.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-68977.rs:29:17
    |
 LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
-   |                 ^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `INT_BITS`
+   |                 ^^^^^^^^ cannot perform const operation using `INT_BITS`
    |
-   = help: it is currently only allowed to use either `INT_BITS` or `{ INT_BITS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `INT_BITS`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-68977.rs:29:28
    |
 LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
-   |                            ^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `FRAC_BITS`
+   |                            ^^^^^^^^^ cannot perform const operation using `FRAC_BITS`
    |
-   = help: it is currently only allowed to use either `FRAC_BITS` or `{ FRAC_BITS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs
index 02e634e..4fea94c 100644
--- a/src/test/ui/const-generics/issues/issue-68977.rs
+++ b/src/test/ui/const-generics/issues/issue-68977.rs
@@ -27,8 +27,8 @@
 
 type FxpStorageHelper<const INT_BITS: u8, const FRAC_BITS: u8> =
     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
-    //[min]~^ ERROR generic parameters must not be used inside of non trivial constant values
-    //[min]~| ERROR generic parameters must not be used inside of non trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
+    //[min]~| ERROR generic parameters may not be used in const operations
 
 struct Fxp<const INT_BITS: u8, const FRAC_BITS: u8>
 where
diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr
index d3e9887..d960d95 100644
--- a/src/test/ui/const-generics/issues/issue-72787.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr
@@ -1,34 +1,34 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:11:17
    |
 LL |     Condition<{ LHS <= RHS }>: True
-   |                 ^^^ non-trivial anonymous constants must not depend on the parameter `LHS`
+   |                 ^^^ cannot perform const operation using `LHS`
    |
-   = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `LHS`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:11:24
    |
 LL |     Condition<{ LHS <= RHS }>: True
-   |                        ^^^ non-trivial anonymous constants must not depend on the parameter `RHS`
+   |                        ^^^ cannot perform const operation using `RHS`
    |
-   = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `RHS`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:26:25
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
-   |                         ^ non-trivial anonymous constants must not depend on the parameter `I`
+   |                         ^ cannot perform const operation using `I`
    |
-   = help: it is currently only allowed to use either `I` or `{ I }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `I`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:26:36
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
-   |                                    ^ non-trivial anonymous constants must not depend on the parameter `J`
+   |                                    ^ cannot perform const operation using `J`
    |
-   = help: it is currently only allowed to use either `J` or `{ J }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `J`
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72787.rs:22:26
diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs
index 45c2019..57572e2 100644
--- a/src/test/ui/const-generics/issues/issue-72787.rs
+++ b/src/test/ui/const-generics/issues/issue-72787.rs
@@ -10,8 +10,8 @@
 impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
     Condition<{ LHS <= RHS }>: True
 //[full]~^ Error constant expression depends on a generic parameter
-//[min]~^^ Error generic parameters must not be used inside of non trivial constant values
-//[min]~| Error generic parameters must not be used inside of non trivial constant values
+//[min]~^^ Error generic parameters may not be used in const operations
+//[min]~| Error generic parameters may not be used in const operations
 {
 }
 impl True for Condition<true> {}
@@ -28,8 +28,8 @@
 //[full]~| constant expression depends on a generic parameter
 //[full]~| constant expression depends on a generic parameter
 //[full]~| constant expression depends on a generic parameter
-//[min]~^^^^^ Error generic parameters must not be used inside of non trivial constant values
-//[min]~| Error generic parameters must not be used inside of non trivial constant values
+//[min]~^^^^^ Error generic parameters may not be used in const operations
+//[min]~| Error generic parameters may not be used in const operations
     // Condition<{ 8 - I <= 8 - J }>: True,
 {
     fn print() {
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
index 48a1f0b..9fec3eb 100644
--- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72819-generic-in-const-eval.rs:9:17
    |
 LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue,
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
index b653b91..6182042 100644
--- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
@@ -8,7 +8,7 @@
 struct Arr<const N: usize>
 where Assert::<{N < usize::max_value() / 2}>: IsTrue,
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 {
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-75299.rs b/src/test/ui/const-generics/issues/issue-75299.rs
new file mode 100644
index 0000000..23f30a1
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-75299.rs
@@ -0,0 +1,11 @@
+// compile-flags: -Zmir-opt-level=3
+// run-pass
+
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+fn main() {
+    fn foo<const N: usize>() -> [u8; N] {
+        [0; N]
+    }
+    let _x = foo::<1>();
+}
diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs
index 0a16ca1..9fdbbff 100644
--- a/src/test/ui/const-generics/issues/issue-76595.rs
+++ b/src/test/ui/const-generics/issues/issue-76595.rs
@@ -14,5 +14,4 @@
 fn main() {
     test::<2>();
     //~^ ERROR wrong number of type
-    //~| ERROR constant expression depends
 }
diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr
index bbc8169..f258d29 100644
--- a/src/test/ui/const-generics/issues/issue-76595.stderr
+++ b/src/test/ui/const-generics/issues/issue-76595.stderr
@@ -4,17 +4,6 @@
 LL |     test::<2>();
    |     ^^^^^^^^^ expected 1 type argument
 
-error: constant expression depends on a generic parameter
-  --> $DIR/issue-76595.rs:15:5
-   |
-LL | fn test<T, const P: usize>() where Bool<{core::mem::size_of::<T>() > 4}>: True {
-   |                                         ------------------------------- required by this bound in `test`
-...
-LL |     test::<2>();
-   |     ^^^^^^^^^
-   |
-   = note: this may fail depending on what value the parameter takes
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
index a39495e..c10db84 100644
--- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-76701-ty-param-in-const.rs:6:46
    |
 LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
-   |                                              ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                              ^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-76701-ty-param-in-const.rs:12:42
    |
 LL | fn const_param<const N: usize>() -> [u8; N + 1] {
-   |                                          ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                          ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
index 9252b59..9051c36 100644
--- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
+++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
@@ -5,13 +5,13 @@
 
 fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
     todo!()
 }
 
 fn const_param<const N: usize>() -> [u8; N + 1] {
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs
index f9cb0d2..8257ffb 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-expression.rs
+++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs
@@ -7,19 +7,19 @@
 }
 
 struct Break0<const N: usize>([u8; { N + 1 }]);
-//~^ ERROR generic parameters must not be used inside of non trivial constant values
+//~^ ERROR generic parameters may not be used in const operations
 
 struct Break1<const N: usize>([u8; { { N } }]);
-//~^ ERROR generic parameters must not be used inside of non trivial constant values
+//~^ ERROR generic parameters may not be used in const operations
 
 fn break2<const N: usize>() {
     let _: [u8; N + 1];
-    //~^ ERROR generic parameters must not be used inside of non trivial constant values
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 fn break3<const N: usize>() {
     let _ = [0; N + 1];
-    //~^ ERROR generic parameters must not be used inside of non trivial constant values
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 trait Foo {
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
index baed8d1..73768ac0 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
+++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
@@ -1,34 +1,34 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:9:38
    |
 LL | struct Break0<const N: usize>([u8; { N + 1 }]);
-   |                                      ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                      ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:12:40
    |
 LL | struct Break1<const N: usize>([u8; { { N } }]);
-   |                                        ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                        ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:16:17
    |
 LL |     let _: [u8; N + 1];
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:21:17
    |
 LL |     let _ = [0; N + 1];
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs
new file mode 100644
index 0000000..02944e2
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs
@@ -0,0 +1,27 @@
+#![feature(min_const_generics)]
+
+// This test checks that non-static lifetimes are prohibited under `min_const_generics`. It
+// currently emits an error with `min_const_generics`. This will ICE under `const_generics`.
+
+fn test<const N: usize>() {}
+
+fn issue_75323_and_74447_1<'a>() -> &'a () {
+    test::<{ let _: &'a (); 3 },>();
+   //~^ ERROR a non-static lifetime is not allowed in a `const`
+    &()
+}
+
+fn issue_75323_and_74447_2() {
+    test::<{ let _: &(); 3 },>();
+}
+
+fn issue_75323_and_74447_3() {
+    test::<{ let _: &'static (); 3 },>();
+}
+
+fn issue_73375<'a>() {
+    [(); (|_: &'a u8| (), 0).1];
+    //~^ ERROR a non-static lifetime is not allowed in a `const`
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr
new file mode 100644
index 0000000..cdfd491
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr
@@ -0,0 +1,21 @@
+error[E0658]: a non-static lifetime is not allowed in a `const`
+  --> $DIR/forbid-non-static-lifetimes.rs:9:22
+   |
+LL |     test::<{ let _: &'a (); 3 },>();
+   |                      ^^
+   |
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+
+error[E0658]: a non-static lifetime is not allowed in a `const`
+  --> $DIR/forbid-non-static-lifetimes.rs:23:16
+   |
+LL |     [(); (|_: &'a u8| (), 0).1];
+   |                ^^
+   |
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: add `#![feature(const_generics)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
index edb77a8..64da5e0 100644
--- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
+++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/self-ty-in-const-1.rs:4:41
    |
 LL |     fn t1() -> [u8; std::mem::size_of::<Self>()];
-   |                                         ^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |                                         ^^^^ cannot perform const operation using `Self`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/self-ty-in-const-1.rs:14:41
diff --git a/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.rs b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.rs
new file mode 100644
index 0000000..0ef1710
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.rs
@@ -0,0 +1,8 @@
+#![feature(min_const_generics)]
+
+fn a<const X: &'static [u32]>() {}
+//~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter
+
+fn main() {
+    a::<{&[]}>();
+}
diff --git a/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr
new file mode 100644
index 0000000..cc32d8a
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr
@@ -0,0 +1,11 @@
+error: `&'static [u32]` is forbidden as the type of a const generic parameter
+  --> $DIR/static-reference-array-const-param.rs:3:15
+   |
+LL | fn a<const X: &'static [u32]>() {}
+   |               ^^^^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs
new file mode 100644
index 0000000..dfa1ece
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs
@@ -0,0 +1,12 @@
+#![feature(min_const_generics)]
+
+struct Const<const P: &'static ()>;
+//~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
+
+fn main() {
+    const A: &'static () = unsafe {
+        std::mem::transmute(10 as *const ())
+    };
+
+    let _ = Const::<{A}>;
+}
diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr
new file mode 100644
index 0000000..063120a
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr
@@ -0,0 +1,11 @@
+error: `&'static ()` is forbidden as the type of a const generic parameter
+  --> $DIR/transmute-const-param-static-reference.rs:3:23
+   |
+LL | struct Const<const P: &'static ()>;
+   |                       ^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr
index 671f110..8a1462c 100644
--- a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr
+++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: constant expression depends on a generic parameter
   --> $DIR/unify-fixpoint.rs:9:32
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
index e545ae8..39aa808 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
@@ -6,13 +6,13 @@
    |
    = note: using type defaults and const parameters in the same parameter list is currently not permitted
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
    |
 LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
-   |                                            ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                            ^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error: constant values inside of type parameter defaults must not depend on generic parameters
   --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
index e52773c..51f0cff 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
@@ -6,7 +6,7 @@
 
 struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
 //[full]~^ ERROR constant values inside of type parameter defaults
-//[min]~^^ ERROR generic parameters must not be used inside of non trivial
+//[min]~^^ ERROR generic parameters may not be used in const operations
 
 // FIXME(const_generics:defaults): We still don't know how to we deal with type defaults.
 struct Bar<T = [u8; N], const N: usize>(T);
diff --git a/src/test/ui/const-generics/wf-misc.min.stderr b/src/test/ui/const-generics/wf-misc.min.stderr
index f2acb8f..935f12d 100644
--- a/src/test/ui/const-generics/wf-misc.min.stderr
+++ b/src/test/ui/const-generics/wf-misc.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/wf-misc.rs:9:17
    |
 LL |     let _: [u8; N + 1];
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/wf-misc.rs:17:21
    |
 LL |     let _: Const::<{N + 1}>;
-   |                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                     ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs
index e6f7a99..103c580 100644
--- a/src/test/ui/const-generics/wf-misc.rs
+++ b/src/test/ui/const-generics/wf-misc.rs
@@ -8,7 +8,7 @@
 pub fn arr_len<const N: usize>() {
     let _: [u8; N + 1];
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non trivial
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 struct Const<const N: usize>;
@@ -16,7 +16,7 @@
 pub fn func_call<const N: usize>() {
     let _: Const::<{N + 1}>;
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non trivial
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
diff --git a/src/test/ui/const-suggest-feature.rs b/src/test/ui/const-suggest-feature.rs
index 89fafbb..d11b91e 100644
--- a/src/test/ui/const-suggest-feature.rs
+++ b/src/test/ui/const-suggest-feature.rs
@@ -2,8 +2,6 @@
     *std::ptr::null_mut() = 0;
     //~^ ERROR dereferencing raw pointers in constants is unstable
     //~| HELP add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
-    //~| ERROR constant contains unimplemented expression type
-    //~| HELP add `#![feature(const_mut_refs)]` to the crate attributes to enable
 };
 
 fn main() {}
diff --git a/src/test/ui/const-suggest-feature.stderr b/src/test/ui/const-suggest-feature.stderr
index 6b91df6..1ccc3d7 100644
--- a/src/test/ui/const-suggest-feature.stderr
+++ b/src/test/ui/const-suggest-feature.stderr
@@ -7,15 +7,6 @@
    = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
    = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const-suggest-feature.rs:2:5
-   |
-LL |     *std::ptr::null_mut() = 0;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0019, E0658.
-For more information about an error, try `rustc --explain E0019`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr
index e2a3e4d..276fb71 100644
--- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr
+++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr
@@ -2,7 +2,7 @@
   --> $DIR/ice-assert-fail-div-by-zero.rs:11:5
    |
 LL |     f.0 / 0;
-   |     ^^^^^^^ attempt to divide _ by zero
+   |     ^^^^^^^ attempt to divide `_` by zero
    |
 note: the lint level is defined here
   --> $DIR/ice-assert-fail-div-by-zero.rs:5:9
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index 08c0231..5916ea6 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -2,7 +2,7 @@
   --> $DIR/array-literal-index-oob.rs:7:8
    |
 LL |     &{ [1, 2, 3][4] };
-   |        ^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 4
+   |        ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4
    |
 note: the lint level is defined here
   --> $DIR/array-literal-index-oob.rs:4:20
diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr
index cd27331..db64ebe 100644
--- a/src/test/ui/consts/assoc_const_generic_impl.stderr
+++ b/src/test/ui/consts/assoc_const_generic_impl.stderr
@@ -4,7 +4,7 @@
 LL |     const I_AM_ZERO_SIZED: ()  = [()][std::mem::size_of::<Self>()];
    |     -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |                                  |
-   |                                  index out of bounds: the len is 1 but the index is 4
+   |                                  index out of bounds: the length is 1 but the index is 4
    |
 note: the lint level is defined here
   --> $DIR/assoc_const_generic_impl.rs:3:9
diff --git a/src/test/ui/consts/async-block.rs b/src/test/ui/consts/async-block.rs
new file mode 100644
index 0000000..1fa2a61
--- /dev/null
+++ b/src/test/ui/consts/async-block.rs
@@ -0,0 +1,8 @@
+// From <https://github.com/rust-lang/rust/issues/77361>
+
+// edition:2018
+
+const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 };
+//~^ `async` block
+
+fn main() {}
diff --git a/src/test/ui/consts/async-block.stderr b/src/test/ui/consts/async-block.stderr
new file mode 100644
index 0000000..99f4706
--- /dev/null
+++ b/src/test/ui/consts/async-block.stderr
@@ -0,0 +1,8 @@
+error: `async` blocks are not allowed in constants
+  --> $DIR/async-block.rs:5:47
+   |
+LL | const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 };
+   |                                               ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/auxiliary/const_fn_lib.rs b/src/test/ui/consts/auxiliary/const_fn_lib.rs
index 85714ef..bf0b01a 100644
--- a/src/test/ui/consts/auxiliary/const_fn_lib.rs
+++ b/src/test/ui/consts/auxiliary/const_fn_lib.rs
@@ -1,6 +1,6 @@
 // Crate that exports a const fn. Used for testing cross-crate.
 
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 #![crate_type="rlib"]
 
 pub const fn foo() -> usize { 22 }
diff --git a/src/test/ui/consts/const-address-of-mut.rs b/src/test/ui/consts/const-address-of-mut.rs
index fe9188c..3788088 100644
--- a/src/test/ui/consts/const-address-of-mut.rs
+++ b/src/test/ui/consts/const-address-of-mut.rs
@@ -1,14 +1,14 @@
 #![feature(raw_ref_op)]
 
-const A: () = { let mut x = 2; &raw mut x; };           //~ ERROR `&raw mut` is not allowed
+const A: () = { let mut x = 2; &raw mut x; };           //~ mutable reference
 
-static B: () = { let mut x = 2; &raw mut x; };          //~ ERROR `&raw mut` is not allowed
+static B: () = { let mut x = 2; &raw mut x; };          //~ mutable reference
 
-static mut C: () = { let mut x = 2; &raw mut x; };      //~ ERROR `&raw mut` is not allowed
+static mut C: () = { let mut x = 2; &raw mut x; };      //~ mutable reference
 
 const fn foo() {
     let mut x = 0;
-    let y = &raw mut x;                                 //~ ERROR `&raw mut` is not allowed
+    let y = &raw mut x;                                 //~ mutable reference
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/const-address-of-mut.stderr b/src/test/ui/consts/const-address-of-mut.stderr
index 1d9a325..ec2dac5 100644
--- a/src/test/ui/consts/const-address-of-mut.stderr
+++ b/src/test/ui/consts/const-address-of-mut.stderr
@@ -1,31 +1,22 @@
-error[E0658]: `&raw mut` is not allowed in constants
+error[E0764]: raw mutable references are not allowed in constants
   --> $DIR/const-address-of-mut.rs:3:32
    |
 LL | const A: () = { let mut x = 2; &raw mut x; };
-   |                                ^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                ^^^^^^^^^^ `&raw mut` is only allowed in `const fn`
 
-error[E0658]: `&raw mut` is not allowed in statics
+error[E0764]: raw mutable references are not allowed in statics
   --> $DIR/const-address-of-mut.rs:5:33
    |
 LL | static B: () = { let mut x = 2; &raw mut x; };
-   |                                 ^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                 ^^^^^^^^^^ `&raw mut` is only allowed in `const fn`
 
-error[E0658]: `&raw mut` is not allowed in statics
+error[E0764]: raw mutable references are not allowed in statics
   --> $DIR/const-address-of-mut.rs:7:37
    |
 LL | static mut C: () = { let mut x = 2; &raw mut x; };
-   |                                     ^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                     ^^^^^^^^^^ `&raw mut` is only allowed in `const fn`
 
-error[E0658]: `&raw mut` is not allowed in constant functions
+error[E0658]: raw mutable references are not allowed in constant functions
   --> $DIR/const-address-of-mut.rs:11:13
    |
 LL |     let y = &raw mut x;
@@ -36,4 +27,5 @@
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-array-oob.rs b/src/test/ui/consts/const-array-oob.rs
index 1174a76..eca2fe1 100644
--- a/src/test/ui/consts/const-array-oob.rs
+++ b/src/test/ui/consts/const-array-oob.rs
@@ -5,7 +5,7 @@
 
 const BLUB: [u32; FOO[4]] = [5, 6];
 //~^ ERROR evaluation of constant value failed [E0080]
-//~| index out of bounds: the len is 3 but the index is 4
+//~| index out of bounds: the length is 3 but the index is 4
 
 fn main() {
     let _ = BAR;
diff --git a/src/test/ui/consts/const-array-oob.stderr b/src/test/ui/consts/const-array-oob.stderr
index f25cac5..1aa3e88 100644
--- a/src/test/ui/consts/const-array-oob.stderr
+++ b/src/test/ui/consts/const-array-oob.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-array-oob.rs:6:19
    |
 LL | const BLUB: [u32; FOO[4]] = [5, 6];
-   |                   ^^^^^^ index out of bounds: the len is 3 but the index is 4
+   |                   ^^^^^^ index out of bounds: the length is 3 but the index is 4
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-block-non-item-statement-3.rs b/src/test/ui/consts/const-block-non-item-statement-3.rs
index 10a4c31..c513946 100644
--- a/src/test/ui/consts/const-block-non-item-statement-3.rs
+++ b/src/test/ui/consts/const-block-non-item-statement-3.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![allow(dead_code)]
+#![allow(dead_code, unused)]
 
 type Array = [u32; {  let x = 2; 5 }];
 
diff --git a/src/test/ui/consts/const-block-non-item-statement-rpass.rs b/src/test/ui/consts/const-block-non-item-statement-rpass.rs
index a1b9b58..3e52eb5 100644
--- a/src/test/ui/consts/const-block-non-item-statement-rpass.rs
+++ b/src/test/ui/consts/const-block-non-item-statement-rpass.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![allow(dead_code)]
+#![allow(dead_code, unused)]
 
 #[repr(u8)]
 enum Foo {
diff --git a/src/test/ui/consts/const-err-early.stderr b/src/test/ui/consts/const-err-early.stderr
index 0cb7751..36b36db 100644
--- a/src/test/ui/consts/const-err-early.stderr
+++ b/src/test/ui/consts/const-err-early.stderr
@@ -4,7 +4,7 @@
 LL | pub const A: i8 = -std::i8::MIN;
    | ------------------^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to negate i8::MIN which would overflow
+   |                   attempt to negate `i8::MIN`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/const-err-early.rs:1:9
@@ -18,7 +18,7 @@
 LL | pub const B: u8 = 200u8 + 200u8;
    | ------------------^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to compute `200_u8 + 200_u8` which would overflow
+   |                   attempt to compute `200_u8 + 200_u8`, which would overflow
 
 error: any use of this value will cause an error
   --> $DIR/const-err-early.rs:5:19
@@ -26,7 +26,7 @@
 LL | pub const C: u8 = 200u8 * 4;
    | ------------------^^^^^^^^^-
    |                   |
-   |                   attempt to compute `200_u8 * 4_u8` which would overflow
+   |                   attempt to compute `200_u8 * 4_u8`, which would overflow
 
 error: any use of this value will cause an error
   --> $DIR/const-err-early.rs:6:19
@@ -34,7 +34,7 @@
 LL | pub const D: u8 = 42u8 - (42u8 + 1);
    | ------------------^^^^^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to compute `42_u8 - 43_u8` which would overflow
+   |                   attempt to compute `42_u8 - 43_u8`, which would overflow
 
 error: any use of this value will cause an error
   --> $DIR/const-err-early.rs:7:19
@@ -42,7 +42,7 @@
 LL | pub const E: u8 = [5u8][1];
    | ------------------^^^^^^^^-
    |                   |
-   |                   index out of bounds: the len is 1 but the index is 1
+   |                   index out of bounds: the length is 1 but the index is 1
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr
index a0c91ff..5b688d4 100644
--- a/src/test/ui/consts/const-err-multi.stderr
+++ b/src/test/ui/consts/const-err-multi.stderr
@@ -4,7 +4,7 @@
 LL | pub const A: i8 = -std::i8::MIN;
    | ------------------^^^^^^^^^^^^^-
    |                   |
-   |                   attempt to negate i8::MIN which would overflow
+   |                   attempt to negate `i8::MIN`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/const-err-multi.rs:1:9
diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr
index ea27aa8..693b74c 100644
--- a/src/test/ui/consts/const-err.stderr
+++ b/src/test/ui/consts/const-err.stderr
@@ -4,7 +4,7 @@
 LL | const FOO: u8 = [5u8][1];
    | ----------------^^^^^^^^-
    |                 |
-   |                 index out of bounds: the len is 1 but the index is 1
+   |                 index out of bounds: the length is 1 but the index is 1
    |
 note: the lint level is defined here
   --> $DIR/const-err.rs:5:9
diff --git a/src/test/ui/consts/const-err2.noopt.stderr b/src/test/ui/consts/const-err2.noopt.stderr
index 687ffc4..2473632 100644
--- a/src/test/ui/consts/const-err2.noopt.stderr
+++ b/src/test/ui/consts/const-err2.noopt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-err2.rs:19:13
    |
 LL |     let a = -std::i8::MIN;
-   |             ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
+   |             ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@
   --> $DIR/const-err2.rs:21:18
    |
 LL |     let a_i128 = -std::i128::MIN;
-   |                  ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
+   |                  ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:23:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
-   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
+   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:25:18
    |
 LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:27:13
    |
 LL |     let c = 200u8 * 4;
-   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
+   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:29:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
-   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
+   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/const-err2.rs:31:14
    |
 LL |     let _e = [5u8][1];
-   |              ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |              ^^^^^^^^ index out of bounds: the length is 1 but the index is 1
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
diff --git a/src/test/ui/consts/const-err2.opt.stderr b/src/test/ui/consts/const-err2.opt.stderr
index 687ffc4..2473632 100644
--- a/src/test/ui/consts/const-err2.opt.stderr
+++ b/src/test/ui/consts/const-err2.opt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-err2.rs:19:13
    |
 LL |     let a = -std::i8::MIN;
-   |             ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
+   |             ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@
   --> $DIR/const-err2.rs:21:18
    |
 LL |     let a_i128 = -std::i128::MIN;
-   |                  ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
+   |                  ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:23:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
-   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
+   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:25:18
    |
 LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:27:13
    |
 LL |     let c = 200u8 * 4;
-   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
+   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:29:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
-   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
+   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/const-err2.rs:31:14
    |
 LL |     let _e = [5u8][1];
-   |              ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |              ^^^^^^^^ index out of bounds: the length is 1 but the index is 1
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
diff --git a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr
index 687ffc4..2473632 100644
--- a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr
+++ b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-err2.rs:19:13
    |
 LL |     let a = -std::i8::MIN;
-   |             ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow
+   |             ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@
   --> $DIR/const-err2.rs:21:18
    |
 LL |     let a_i128 = -std::i128::MIN;
-   |                  ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow
+   |                  ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:23:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
-   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow
+   |             ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:25:18
    |
 LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:27:13
    |
 LL |     let c = 200u8 * 4;
-   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow
+   |             ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/const-err2.rs:29:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
-   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow
+   |             ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/const-err2.rs:31:14
    |
 LL |     let _e = [5u8][1];
-   |              ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |              ^^^^^^^^ index out of bounds: the length is 1 but the index is 1
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs
index 4d3c714..037c6f9 100644
--- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs
+++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs
@@ -1,7 +1,7 @@
 // New test for #53818: modifying static memory at compile-time is not allowed.
 // The test should never compile successfully
 
-#![feature(const_raw_ptr_deref)]
+#![feature(const_raw_ptr_deref, const_mut_refs)]
 
 use std::cell::UnsafeCell;
 
@@ -13,7 +13,7 @@
 static FOO: Foo = Foo(UnsafeCell::new(42));
 
 static BAR: () = unsafe {
-    *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type
+    *FOO.0.get() = 5; //~ ERROR
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr
index 14dcc07..296a6bf 100644
--- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr
+++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr
@@ -1,11 +1,9 @@
-error[E0019]: static contains unimplemented expression type
+error[E0080]: could not evaluate static initializer
   --> $DIR/assign-to-static-within-other-static-2.rs:16:5
    |
 LL |     *FOO.0.get() = 5;
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |     ^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0019`.
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
index 62f3398..65dfbd8 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
@@ -4,7 +4,7 @@
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
    | ------------------^^^^^---------------------------
    |                   |
-   |                   attempt to compute `5_u32 - 6_u32` which would overflow
+   |                   attempt to compute `5_u32 - 6_u32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/conditional_array_execution.rs:3:9
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr
index dd79cbd..0ae5178 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-eval-overflow-3.rs:20:11
    |
 LL |     = [0; (i8::MAX + 1) as usize];
-   |           ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
+   |           ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr
index 30c52a8..e548fc2 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-eval-overflow-4.rs:13:13
    |
 LL |     : [u32; (i8::MAX as i8 + 1i8) as usize]
-   |             ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
+   |             ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr
index 2ad557a..51a810b 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr
@@ -4,7 +4,7 @@
 LL | / const VALS_I8: (i8,) =
 LL | |     (
 LL | |      i8::MIN - 1,
-   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8` which would overflow
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow
 LL | |      );
    | |_______-
    |
@@ -20,7 +20,7 @@
 LL | / const VALS_I16: (i16,) =
 LL | |     (
 LL | |      i16::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow
 LL | |      );
    | |_______-
 
@@ -30,7 +30,7 @@
 LL | / const VALS_I32: (i32,) =
 LL | |     (
 LL | |      i32::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow
 LL | |      );
    | |_______-
 
@@ -40,7 +40,7 @@
 LL | / const VALS_I64: (i64,) =
 LL | |     (
 LL | |      i64::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow
 LL | |      );
    | |_______-
 
@@ -50,7 +50,7 @@
 LL | / const VALS_U8: (u8,) =
 LL | |     (
 LL | |      u8::MIN - 1,
-   | |      ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8` which would overflow
+   | |      ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow
 LL | |      );
    | |_______-
 
@@ -59,7 +59,7 @@
    |
 LL | / const VALS_U16: (u16,) = (
 LL | |      u16::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow
 LL | |      );
    | |_______-
 
@@ -68,7 +68,7 @@
    |
 LL | / const VALS_U32: (u32,) = (
 LL | |      u32::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
 LL | |      );
    | |_______-
 
@@ -78,7 +78,7 @@
 LL | / const VALS_U64: (u64,) =
 LL | |     (
 LL | |      u64::MIN - 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow
 LL | |      );
    | |_______-
 
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr
index fce616b..eec440f 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr
@@ -4,7 +4,7 @@
 LL | / const VALS_I8: (i8,) =
 LL | |     (
 LL | |      i8::MAX + 1,
-   | |      ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow
 LL | |      );
    | |_______-
    |
@@ -20,7 +20,7 @@
 LL | / const VALS_I16: (i16,) =
 LL | |     (
 LL | |      i16::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow
 LL | |      );
    | |_______-
 
@@ -30,7 +30,7 @@
 LL | / const VALS_I32: (i32,) =
 LL | |     (
 LL | |      i32::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow
 LL | |      );
    | |_______-
 
@@ -40,7 +40,7 @@
 LL | / const VALS_I64: (i64,) =
 LL | |     (
 LL | |      i64::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow
 LL | |      );
    | |_______-
 
@@ -50,7 +50,7 @@
 LL | / const VALS_U8: (u8,) =
 LL | |     (
 LL | |      u8::MAX + 1,
-   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8` which would overflow
+   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
 LL | |      );
    | |_______-
 
@@ -59,7 +59,7 @@
    |
 LL | / const VALS_U16: (u16,) = (
 LL | |      u16::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow
 LL | |      );
    | |_______-
 
@@ -68,7 +68,7 @@
    |
 LL | / const VALS_U32: (u32,) = (
 LL | |      u32::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow
 LL | |      );
    | |_______-
 
@@ -78,7 +78,7 @@
 LL | / const VALS_U64: (u64,) =
 LL | |     (
 LL | |      u64::MAX + 1,
-   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow
 LL | |      );
    | |_______-
 
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr
index 7620152..e44f94c 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr
@@ -4,7 +4,7 @@
 LL | / const VALS_I8: (i8,) =
 LL | |     (
 LL | |      i8::MIN * 2,
-   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8` which would overflow
+   | |      ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow
 LL | |      );
    | |_______-
    |
@@ -20,7 +20,7 @@
 LL | / const VALS_I16: (i16,) =
 LL | |     (
 LL | |      i16::MIN * 2,
-   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow
 LL | |      );
    | |_______-
 
@@ -30,7 +30,7 @@
 LL | / const VALS_I32: (i32,) =
 LL | |     (
 LL | |      i32::MIN * 2,
-   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow
 LL | |      );
    | |_______-
 
@@ -40,7 +40,7 @@
 LL | / const VALS_I64: (i64,) =
 LL | |     (
 LL | |      i64::MIN * 2,
-   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow
 LL | |      );
    | |_______-
 
@@ -50,7 +50,7 @@
 LL | / const VALS_U8: (u8,) =
 LL | |     (
 LL | |      u8::MAX * 2,
-   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8` which would overflow
+   | |      ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow
 LL | |      );
    | |_______-
 
@@ -59,7 +59,7 @@
    |
 LL | / const VALS_U16: (u16,) = (
 LL | |      u16::MAX * 2,
-   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow
 LL | |      );
    | |_______-
 
@@ -68,7 +68,7 @@
    |
 LL | / const VALS_U32: (u32,) = (
 LL | |      u32::MAX * 2,
-   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow
 LL | |      );
    | |_______-
 
@@ -78,7 +78,7 @@
 LL | / const VALS_U64: (u64,) =
 LL | |     (
 LL | |      u64::MAX * 2,
-   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64` which would overflow
+   | |      ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow
 LL | |      );
    | |_______-
 
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
index d0ae940..ab18020 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr
@@ -10,11 +10,23 @@
    |
 LL |     X_CONST(x)
    |     ^^^^^^^^^^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr.rs:19:14
+   |
+LL | const fn foo(x: fn(usize) -> usize, y: usize)  -> usize {
+   |              ^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr.rs:20:5
+   |
+LL |     x(y)
+   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr.rs:20:5
    |
 LL |     x(y)
    |     ^^^^
 
-warning: 1 warning emitted
+error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
+
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
index 90ee2af..822d4af 100644
--- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
+++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
@@ -20,6 +20,16 @@
 
 warning: skipping const checks
    |
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr_fail2.rs:12:14
+   |
+LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
+   |              ^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/const_fn_ptr_fail2.rs:13:5
+   |
+LL |     x(y)
+   |     ^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_fn_ptr_fail2.rs:13:5
    |
diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs
index 3e5112b..ada9fee 100644
--- a/src/test/ui/consts/const-eval/const_panic.rs
+++ b/src/test/ui/consts/const-eval/const_panic.rs
@@ -1,11 +1,26 @@
 #![feature(const_panic)]
 #![crate_type = "lib"]
 
-pub const Z: () = panic!("cheese");
+const Z: () = std::panic!("cheese");
 //~^ ERROR any use of this value will cause an error
 
-pub const Y: () = unreachable!();
+const Z2: () = std::panic!();
 //~^ ERROR any use of this value will cause an error
 
-pub const X: () = unimplemented!();
+const Y: () = std::unreachable!();
+//~^ ERROR any use of this value will cause an error
+
+const X: () = std::unimplemented!();
+//~^ ERROR any use of this value will cause an error
+
+const Z_CORE: () = core::panic!("cheese");
+//~^ ERROR any use of this value will cause an error
+
+const Z2_CORE: () = core::panic!();
+//~^ ERROR any use of this value will cause an error
+
+const Y_CORE: () = core::unreachable!();
+//~^ ERROR any use of this value will cause an error
+
+const X_CORE: () = core::unimplemented!();
 //~^ ERROR any use of this value will cause an error
diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr
index 679d8f2..e4ca1f4 100644
--- a/src/test/ui/consts/const-eval/const_panic.stderr
+++ b/src/test/ui/consts/const-eval/const_panic.stderr
@@ -1,33 +1,83 @@
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:4:19
+  --> $DIR/const_panic.rs:4:15
    |
-LL | pub const Z: () = panic!("cheese");
-   | ------------------^^^^^^^^^^^^^^^^-
-   |                   |
-   |                   the evaluated program panicked at 'cheese', $DIR/const_panic.rs:4:19
+LL | const Z: () = std::panic!("cheese");
+   | --------------^^^^^^^^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'cheese', $DIR/const_panic.rs:4:15
    |
    = note: `#[deny(const_err)]` on by default
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:7:19
+  --> $DIR/const_panic.rs:7:16
    |
-LL | pub const Y: () = unreachable!();
-   | ------------------^^^^^^^^^^^^^^-
-   |                   |
-   |                   the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:7:19
+LL | const Z2: () = std::panic!();
+   | ---------------^^^^^^^^^^^^^-
+   |                |
+   |                the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:7:16
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:10:19
+  --> $DIR/const_panic.rs:10:15
    |
-LL | pub const X: () = unimplemented!();
-   | ------------------^^^^^^^^^^^^^^^^-
-   |                   |
-   |                   the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:10:19
+LL | const Y: () = std::unreachable!();
+   | --------------^^^^^^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:10:15
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors
+error: any use of this value will cause an error
+  --> $DIR/const_panic.rs:13:15
+   |
+LL | const X: () = std::unimplemented!();
+   | --------------^^^^^^^^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:13:15
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic.rs:16:20
+   |
+LL | const Z_CORE: () = core::panic!("cheese");
+   | -------------------^^^^^^^^^^^^^^^^^^^^^^-
+   |                    |
+   |                    the evaluated program panicked at 'cheese', $DIR/const_panic.rs:16:20
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic.rs:19:21
+   |
+LL | const Z2_CORE: () = core::panic!();
+   | --------------------^^^^^^^^^^^^^^-
+   |                     |
+   |                     the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:19:21
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic.rs:22:20
+   |
+LL | const Y_CORE: () = core::unreachable!();
+   | -------------------^^^^^^^^^^^^^^^^^^^^-
+   |                    |
+   |                    the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:22:20
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic.rs:25:20
+   |
+LL | const X_CORE: () = core::unimplemented!();
+   | -------------------^^^^^^^^^^^^^^^^^^^^^^-
+   |                    |
+   |                    the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:25:20
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/consts/const-eval/const_panic_libcore.rs b/src/test/ui/consts/const-eval/const_panic_libcore.rs
deleted file mode 100644
index e42685e..0000000
--- a/src/test/ui/consts/const-eval/const_panic_libcore.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-#![no_std]
-#![crate_type = "lib"]
-#![feature(const_panic)]
-
-const Z: () = panic!("cheese");
-//~^ ERROR any use of this value will cause an error
-
-const Y: () = unreachable!();
-//~^ ERROR any use of this value will cause an error
-
-const X: () = unimplemented!();
-//~^ ERROR any use of this value will cause an error
diff --git a/src/test/ui/consts/const-eval/const_panic_libcore.stderr b/src/test/ui/consts/const-eval/const_panic_libcore.stderr
deleted file mode 100644
index 2abf158..0000000
--- a/src/test/ui/consts/const-eval/const_panic_libcore.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore.rs:5:15
-   |
-LL | const Z: () = panic!("cheese");
-   | --------------^^^^^^^^^^^^^^^^-
-   |               |
-   |               the evaluated program panicked at 'cheese', $DIR/const_panic_libcore.rs:5:15
-   |
-   = note: `#[deny(const_err)]` on by default
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore.rs:8:15
-   |
-LL | const Y: () = unreachable!();
-   | --------------^^^^^^^^^^^^^^-
-   |               |
-   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore.rs:8:15
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore.rs:11:15
-   |
-LL | const X: () = unimplemented!();
-   | --------------^^^^^^^^^^^^^^^^-
-   |               |
-   |               the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore.rs:11:15
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_main.rs b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs
similarity index 100%
rename from src/test/ui/consts/const-eval/const_panic_libcore_main.rs
rename to src/test/ui/consts/const-eval/const_panic_libcore_bin.rs
diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr
new file mode 100644
index 0000000..9eeddc4
--- /dev/null
+++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr
@@ -0,0 +1,33 @@
+error: any use of this value will cause an error
+  --> $DIR/const_panic_libcore_bin.rs:9:15
+   |
+LL | const Z: () = panic!("cheese");
+   | --------------^^^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15
+   |
+   = note: `#[deny(const_err)]` on by default
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic_libcore_bin.rs:12:15
+   |
+LL | const Y: () = unreachable!();
+   | --------------^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/const_panic_libcore_bin.rs:15:15
+   |
+LL | const X: () = unimplemented!();
+   | --------------^^^^^^^^^^^^^^^^-
+   |               |
+   |               the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_main.stderr b/src/test/ui/consts/const-eval/const_panic_libcore_main.stderr
deleted file mode 100644
index c5887ff..0000000
--- a/src/test/ui/consts/const-eval/const_panic_libcore_main.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore_main.rs:9:15
-   |
-LL | const Z: () = panic!("cheese");
-   | --------------^^^^^^^^^^^^^^^^-
-   |               |
-   |               the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_main.rs:9:15
-   |
-   = note: `#[deny(const_err)]` on by default
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore_main.rs:12:15
-   |
-LL | const Y: () = unreachable!();
-   | --------------^^^^^^^^^^^^^^-
-   |               |
-   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_main.rs:12:15
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore_main.rs:15:15
-   |
-LL | const X: () = unimplemented!();
-   | --------------^^^^^^^^^^^^^^^^-
-   |               |
-   |               the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_main.rs:15:15
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr
index f06e2c3..7087a6f 100644
--- a/src/test/ui/consts/const-eval/erroneous-const.stderr
+++ b/src/test/ui/consts/const-eval/erroneous-const.stderr
@@ -2,7 +2,7 @@
   --> $DIR/erroneous-const.rs:6:22
    |
 LL |     const VOID: () = [()][2];
-   |                      ^^^^^^^ index out of bounds: the len is 1 but the index is 2
+   |                      ^^^^^^^ index out of bounds: the length is 1 but the index is 2
    |
 note: the lint level is defined here
   --> $DIR/erroneous-const.rs:2:20
@@ -16,7 +16,7 @@
 LL |     const VOID: () = [()][2];
    |     -----------------^^^^^^^-
    |                      |
-   |                      index out of bounds: the len is 1 but the index is 2
+   |                      index out of bounds: the length is 1 but the index is 2
    |
 note: the lint level is defined here
   --> $DIR/erroneous-const.rs:2:9
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
index 33e60dd..8647da9 100644
--- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
@@ -4,7 +4,7 @@
 LL |     const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
    |     --------------------------------------------------------^^^^^---
    |                                                             |
-   |                                                             index out of bounds: the len is 0 but the index is 0
+   |                                                             index out of bounds: the length is 0 but the index is 0
    |
 note: the lint level is defined here
   --> $DIR/index-out-of-bounds-never-type.rs:4:9
diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds.stderr
index 1b2974e..8bb3a0c 100644
--- a/src/test/ui/consts/const-eval/index_out_of_bounds.stderr
+++ b/src/test/ui/consts/const-eval/index_out_of_bounds.stderr
@@ -2,7 +2,7 @@
   --> $DIR/index_out_of_bounds.rs:1:19
    |
 LL | static FOO: i32 = [][0];
-   |                   ^^^^^ index out of bounds: the len is 0 but the index is 0
+   |                   ^^^^^ index out of bounds: the length is 0 but the index is 0
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr
index 4188efd..d247d69 100644
--- a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr
+++ b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr
@@ -2,7 +2,7 @@
   --> $DIR/index_out_of_bounds_propagated.rs:5:5
    |
 LL |     array[1];
-   |     ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |     ^^^^^^^^ index out of bounds: the length is 1 but the index is 1
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr
index b3e1f49..27e067c 100644
--- a/src/test/ui/consts/const-eval/issue-43197.stderr
+++ b/src/test/ui/consts/const-eval/issue-43197.stderr
@@ -4,7 +4,7 @@
 LL |     const X: u32 = 0 - 1;
    |     ---------------^^^^^-
    |                    |
-   |                    attempt to compute `0_u32 - 1_u32` which would overflow
+   |                    attempt to compute `0_u32 - 1_u32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/issue-43197.rs:3:9
@@ -18,7 +18,7 @@
 LL |     const Y: u32 = foo(0 - 1);
    |     -------------------^^^^^--
    |                        |
-   |                        attempt to compute `0_u32 - 1_u32` which would overflow
+   |                        attempt to compute `0_u32 - 1_u32`, which would overflow
 
 error[E0080]: evaluation of constant expression failed
   --> $DIR/issue-43197.rs:14:23
diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr
index e04bf03..ca8885e 100644
--- a/src/test/ui/consts/const-eval/issue-50814-2.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr
@@ -4,7 +4,7 @@
 LL |     const BAR: usize = [5, 6, 7][T::BOO];
    |     -------------------^^^^^^^^^^^^^^^^^-
    |                        |
-   |                        index out of bounds: the len is 3 but the index is 42
+   |                        index out of bounds: the length is 3 but the index is 42
    |
    = note: `#[deny(const_err)]` on by default
 
diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr
index 4be84f8..7327138 100644
--- a/src/test/ui/consts/const-eval/issue-50814.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814.stderr
@@ -4,7 +4,7 @@
 LL |     const MAX: u8 = A::MAX + B::MAX;
    |     ----------------^^^^^^^^^^^^^^^-
    |                     |
-   |                     attempt to compute `u8::MAX + u8::MAX` which would overflow
+   |                     attempt to compute `u8::MAX + u8::MAX`, which would overflow
    |
    = note: `#[deny(const_err)]` on by default
 
diff --git a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
index 59d46ea..bf8bae5 100644
--- a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
+++ b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 
 const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) {
     x
diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
index 32f0062..481e046 100644
--- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
+++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
@@ -12,14 +12,9 @@
 
 static FOO: Foo = Foo(UnsafeCell::new(42));
 
-fn foo() {}
-
 static BAR: () = unsafe {
     *FOO.0.get() = 5;
-    //~^ contains unimplemented expression
-
-    foo();
-    //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
+    //~^ mutation through a reference
 };
 
 fn main() {
diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr
index 44ae1ec..38282c0 100644
--- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr
+++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr
@@ -1,18 +1,12 @@
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/mod-static-with-const-fn.rs:18:5
+error[E0658]: mutation through a reference is not allowed in statics
+  --> $DIR/mod-static-with-const-fn.rs:16:5
    |
 LL |     *FOO.0.get() = 5;
    |     ^^^^^^^^^^^^^^^^
    |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/mod-static-with-const-fn.rs:21:5
-   |
-LL |     foo();
-   |     ^^^^^
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0015, E0019.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
index 5231320..ce83d8e 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/promoted_errors.rs:12:20
    |
 LL |     println!("{}", 0u32 - 1);
-   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
+   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:20
@@ -14,13 +14,13 @@
   --> $DIR/promoted_errors.rs:14:14
    |
 LL |     let _x = 0u32 - 1;
-   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1 / (1 - 1));
-   |                    ^^^^^^^^^^^ attempt to divide 1_i32 by zero
+   |                    ^^^^^^^^^^^ attempt to divide `1_i32` by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:41
@@ -50,13 +50,13 @@
   --> $DIR/promoted_errors.rs:20:14
    |
 LL |     let _x = 1 / (1 - 1);
-   |              ^^^^^^^^^^^ attempt to divide 1_i32 by zero
+   |              ^^^^^^^^^^^ attempt to divide `1_i32` by zero
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:22:20
    |
 LL |     println!("{}", 1 / (false as u32));
-   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
 warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:22:20
@@ -74,7 +74,7 @@
   --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1 / (false as u32);
-   |              ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
 warning: 10 warnings emitted
 
diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
index b411bb2..2c66b17 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/promoted_errors.rs:14:14
    |
 LL |     let _x = 0u32 - 1;
-   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:20
@@ -14,7 +14,7 @@
   --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1 / (1 - 1));
-   |                    ^^^^^^^^^^^ attempt to divide 1_i32 by zero
+   |                    ^^^^^^^^^^^ attempt to divide `1_i32` by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:41
@@ -44,13 +44,13 @@
   --> $DIR/promoted_errors.rs:20:14
    |
 LL |     let _x = 1 / (1 - 1);
-   |              ^^^^^^^^^^^ attempt to divide 1_i32 by zero
+   |              ^^^^^^^^^^^ attempt to divide `1_i32` by zero
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:22:20
    |
 LL |     println!("{}", 1 / (false as u32));
-   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
 warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:22:20
@@ -68,7 +68,7 @@
   --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1 / (false as u32);
-   |              ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
 warning: 9 warnings emitted
 
diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
index 5231320..ce83d8e 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
@@ -2,7 +2,7 @@
   --> $DIR/promoted_errors.rs:12:20
    |
 LL |     println!("{}", 0u32 - 1);
-   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
+   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:20
@@ -14,13 +14,13 @@
   --> $DIR/promoted_errors.rs:14:14
    |
 LL |     let _x = 0u32 - 1;
-   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 1 / (1 - 1));
-   |                    ^^^^^^^^^^^ attempt to divide 1_i32 by zero
+   |                    ^^^^^^^^^^^ attempt to divide `1_i32` by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:41
@@ -50,13 +50,13 @@
   --> $DIR/promoted_errors.rs:20:14
    |
 LL |     let _x = 1 / (1 - 1);
-   |              ^^^^^^^^^^^ attempt to divide 1_i32 by zero
+   |              ^^^^^^^^^^^ attempt to divide `1_i32` by zero
 
 warning: this operation will panic at runtime
   --> $DIR/promoted_errors.rs:22:20
    |
 LL |     println!("{}", 1 / (false as u32));
-   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
 warning: reaching this expression at runtime will panic or abort
   --> $DIR/promoted_errors.rs:22:20
@@ -74,7 +74,7 @@
   --> $DIR/promoted_errors.rs:26:14
    |
 LL |     let _x = 1 / (false as u32);
-   |              ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
 warning: 10 warnings emitted
 
diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr
index ecdba2f..5be0fd9 100644
--- a/src/test/ui/consts/const-eval/pub_const_err.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err.stderr
@@ -4,7 +4,7 @@
 LL | pub const Z: u32 = 0 - 1;
    | -------------------^^^^^-
    |                    |
-   |                    attempt to compute `0_u32 - 1_u32` which would overflow
+   |                    attempt to compute `0_u32 - 1_u32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/pub_const_err.rs:2:9
diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
index b2b6576..55f8a58 100644
--- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
+++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr
@@ -4,7 +4,7 @@
 LL | pub const Z: u32 = 0 - 1;
    | -------------------^^^^^-
    |                    |
-   |                    attempt to compute `0_u32 - 1_u32` which would overflow
+   |                    attempt to compute `0_u32 - 1_u32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/pub_const_err_bin.rs:2:9
diff --git a/src/test/ui/consts/const-eval/shift_overflow.stderr b/src/test/ui/consts/const-eval/shift_overflow.stderr
index 478769c..e8d4076 100644
--- a/src/test/ui/consts/const-eval/shift_overflow.stderr
+++ b/src/test/ui/consts/const-eval/shift_overflow.stderr
@@ -2,7 +2,7 @@
   --> $DIR/shift_overflow.rs:3:9
    |
 LL |     X = 1 << ((u32::MAX as u64) + 1),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by 4294967296_u64 which would overflow
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by `4294967296_u64`, which would overflow
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr
index a13cb87..0cb1379 100644
--- a/src/test/ui/consts/const-eval/unused-broken-const.stderr
+++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr
@@ -4,7 +4,7 @@
 LL | const FOO: i32 = [][0];
    | -----------------^^^^^-
    |                  |
-   |                  index out of bounds: the len is 0 but the index is 0
+   |                  index out of bounds: the length is 0 but the index is 0
    |
    = note: `#[deny(const_err)]` on by default
 
diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs
new file mode 100644
index 0000000..b8b95de
--- /dev/null
+++ b/src/test/ui/consts/const-eval/unwind-abort.rs
@@ -0,0 +1,13 @@
+#![feature(unwind_attributes, const_panic)]
+
+#[unwind(aborts)]
+const fn foo() {
+    panic!() //~ evaluation of constant value failed
+}
+
+const _: () = foo(); //~ any use of this value will cause an error
+// Ensure that the CTFE engine handles calls to `#[unwind(aborts)]` gracefully
+
+fn main() {
+    let _ = foo();
+}
diff --git a/src/test/ui/consts/const-eval/unwind-abort.stderr b/src/test/ui/consts/const-eval/unwind-abort.stderr
new file mode 100644
index 0000000..084beb1
--- /dev/null
+++ b/src/test/ui/consts/const-eval/unwind-abort.stderr
@@ -0,0 +1,21 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/unwind-abort.rs:5:5
+   |
+LL |     panic!()
+   |     ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: any use of this value will cause an error
+  --> $DIR/unwind-abort.rs:8:15
+   |
+LL | const _: () = foo();
+   | --------------^^^^^-
+   |               |
+   |               referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
index 094ae73..645a957 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs
@@ -2,7 +2,8 @@
 
 const extern fn unsize(x: &[u8; 3]) -> &[u8] { x }
 const unsafe extern "C" fn closure() -> fn() { || {} }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
+//~| ERROR function pointer cast
 const unsafe extern fn use_float() { 1.0 + 1.0; }
 //~^ ERROR floating point arithmetic
 const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
index fcc34f3..694e229 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr
@@ -1,14 +1,23 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/const-extern-fn-min-const-fn.rs:4:41
    |
 LL | const unsafe extern "C" fn closure() -> fn() { || {} }
    |                                         ^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
+
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/const-extern-fn-min-const-fn.rs:4:48
+   |
+LL | const unsafe extern "C" fn closure() -> fn() { || {} }
+   |                                                ^^^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
 error[E0658]: floating point arithmetic is not allowed in constant functions
-  --> $DIR/const-extern-fn-min-const-fn.rs:6:38
+  --> $DIR/const-extern-fn-min-const-fn.rs:7:38
    |
 LL | const unsafe extern fn use_float() { 1.0 + 1.0; }
    |                                      ^^^^^^^^^
@@ -17,7 +26,7 @@
    = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constant functions is unstable
-  --> $DIR/const-extern-fn-min-const-fn.rs:8:48
+  --> $DIR/const-extern-fn-min-const-fn.rs:9:48
    |
 LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
    |                                                ^^^^^^^^^^^^
@@ -25,7 +34,6 @@
    = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0658, E0723.
-For more information about an error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-external-macro-const-err.stderr b/src/test/ui/consts/const-external-macro-const-err.stderr
index 06a630d..350e4b2 100644
--- a/src/test/ui/consts/const-external-macro-const-err.stderr
+++ b/src/test/ui/consts/const-external-macro-const-err.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-external-macro-const-err.rs:12:5
    |
 LL |     static_assert!(2 + 2 == 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1
    |
    = note: `#[deny(const_err)]` on by default
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/src/test/ui/consts/const-len-underflow-separate-spans.stderr b/src/test/ui/consts/const-len-underflow-separate-spans.stderr
index eff5058..2ab6d0f 100644
--- a/src/test/ui/consts/const-len-underflow-separate-spans.stderr
+++ b/src/test/ui/consts/const-len-underflow-separate-spans.stderr
@@ -4,7 +4,7 @@
 LL | const LEN: usize = ONE - TWO;
    | -------------------^^^^^^^^^-
    |                    |
-   |                    attempt to compute `1_usize - 2_usize` which would overflow
+   |                    attempt to compute `1_usize - 2_usize`, which would overflow
    |
    = note: `#[deny(const_err)]` on by default
 
diff --git a/src/test/ui/consts/const-len-underflow-subspans.rs b/src/test/ui/consts/const-len-underflow-subspans.rs
index 8ef8ef9..ed77e90 100644
--- a/src/test/ui/consts/const-len-underflow-subspans.rs
+++ b/src/test/ui/consts/const-len-underflow-subspans.rs
@@ -7,5 +7,5 @@
 fn main() {
     let a: [i8; ONE - TWO] = unimplemented!();
     //~^ ERROR evaluation of constant value failed
-    //~| attempt to compute `1_usize - 2_usize` which would overflow
+    //~| attempt to compute `1_usize - 2_usize`, which would overflow
 }
diff --git a/src/test/ui/consts/const-len-underflow-subspans.stderr b/src/test/ui/consts/const-len-underflow-subspans.stderr
index e52e64b..68e958b 100644
--- a/src/test/ui/consts/const-len-underflow-subspans.stderr
+++ b/src/test/ui/consts/const-len-underflow-subspans.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-len-underflow-subspans.rs:8:17
    |
 LL |     let a: [i8; ONE - TWO] = unimplemented!();
-   |                 ^^^^^^^^^ attempt to compute `1_usize - 2_usize` which would overflow
+   |                 ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr
index 7bb4acb..3bcf2b2 100644
--- a/src/test/ui/consts/const-prop-ice.stderr
+++ b/src/test/ui/consts/const-prop-ice.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-prop-ice.rs:4:5
    |
 LL |     [0; 3][3u64 as usize];
-   |     ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3
+   |     ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 3
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
diff --git a/src/test/ui/consts/const-prop-ice2.stderr b/src/test/ui/consts/const-prop-ice2.stderr
index 73405ec..2b65ffc 100644
--- a/src/test/ui/consts/const-prop-ice2.stderr
+++ b/src/test/ui/consts/const-prop-ice2.stderr
@@ -2,7 +2,7 @@
   --> $DIR/const-prop-ice2.rs:6:20
    |
 LL |     println!("{}", xs[Enum::One as usize]);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
diff --git a/src/test/ui/consts/const-slice-oob.rs b/src/test/ui/consts/const-slice-oob.rs
index 1775f35..70852f8 100644
--- a/src/test/ui/consts/const-slice-oob.rs
+++ b/src/test/ui/consts/const-slice-oob.rs
@@ -2,7 +2,7 @@
 
 const FOO: &'static[u32] = &[1, 2, 3];
 const BAR: u32 = FOO[5];
-//~^ index out of bounds: the len is 3 but the index is 5
+//~^ index out of bounds: the length is 3 but the index is 5
 //~| ERROR any use of this value will cause an error
 
 fn main() {
diff --git a/src/test/ui/consts/const-slice-oob.stderr b/src/test/ui/consts/const-slice-oob.stderr
index 7e191a6..0077baf 100644
--- a/src/test/ui/consts/const-slice-oob.stderr
+++ b/src/test/ui/consts/const-slice-oob.stderr
@@ -4,7 +4,7 @@
 LL | const BAR: u32 = FOO[5];
    | -----------------^^^^^^-
    |                  |
-   |                  index out of bounds: the len is 3 but the index is 5
+   |                  index out of bounds: the length is 3 but the index is 5
    |
    = note: `#[deny(const_err)]` on by default
 
diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs
index 9d5ccb8..2fd6e06 100644
--- a/src/test/ui/consts/const_let_assign3.rs
+++ b/src/test/ui/consts/const_let_assign3.rs
@@ -6,23 +6,21 @@
 
 impl S {
     const fn foo(&mut self, x: u32) {
-        //~^ ERROR mutable references
+        //~^ ERROR mutable reference
         self.state = x;
     }
 }
 
 const FOO: S = {
     let mut s = S { state: 42 };
-    s.foo(3); //~ ERROR mutable references are not allowed in constants
+    s.foo(3); //~ ERROR mutable reference
     s
 };
 
 type Array = [u32; {
     let mut x = 2;
-    let y = &mut x;
-//~^ ERROR mutable references are not allowed in constants
+    let y = &mut x; //~ ERROR mutable reference
     *y = 42;
-//~^ ERROR constant contains unimplemented expression type
     *y
 }];
 
diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr
index 15badea..dc86e17 100644
--- a/src/test/ui/consts/const_let_assign3.stderr
+++ b/src/test/ui/consts/const_let_assign3.stderr
@@ -19,15 +19,7 @@
 LL |     let y = &mut x;
    |             ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/const_let_assign3.rs:24:5
-   |
-LL |     *y = 42;
-   |     ^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+error: aborting due to 3 previous errors
 
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0019, E0658, E0764.
-For more information about an error, try `rustc --explain E0019`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/drop-pass.rs b/src/test/ui/consts/control-flow/drop-pass.rs
index 95f954a..2a6d127 100644
--- a/src/test/ui/consts/control-flow/drop-pass.rs
+++ b/src/test/ui/consts/control-flow/drop-pass.rs
@@ -1,6 +1,7 @@
 // run-pass
 // revisions: stock precise
 
+#![allow(unused)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
 
 // `x` is always moved into the final value and is not dropped inside the initializer.
diff --git a/src/test/ui/consts/inline_asm.rs b/src/test/ui/consts/inline_asm.rs
index c2ab97e..b8b7550 100644
--- a/src/test/ui/consts/inline_asm.rs
+++ b/src/test/ui/consts/inline_asm.rs
@@ -1,6 +1,6 @@
 #![feature(llvm_asm)]
 
 const _: () = unsafe { llvm_asm!("nop") };
-//~^ ERROR contains unimplemented expression type
+//~^ ERROR inline assembly
 
 fn main() {}
diff --git a/src/test/ui/consts/inline_asm.stderr b/src/test/ui/consts/inline_asm.stderr
index 0a064c8..6fb6b69 100644
--- a/src/test/ui/consts/inline_asm.stderr
+++ b/src/test/ui/consts/inline_asm.stderr
@@ -1,4 +1,4 @@
-error[E0019]: constant contains unimplemented expression type
+error[E0015]: inline assembly is not allowed in constants
   --> $DIR/inline_asm.rs:3:24
    |
 LL | const _: () = unsafe { llvm_asm!("nop") };
@@ -8,4 +8,4 @@
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0019`.
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/issue-37550.rs b/src/test/ui/consts/issue-37550.rs
index 0486583..15877c5 100644
--- a/src/test/ui/consts/issue-37550.rs
+++ b/src/test/ui/consts/issue-37550.rs
@@ -2,7 +2,7 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 
 const fn x() {
     let t = true;
diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs
index 9d1a8b5..90ea217 100644
--- a/src/test/ui/consts/issue-56164.rs
+++ b/src/test/ui/consts/issue-56164.rs
@@ -1,12 +1,11 @@
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 
 const fn foo() { (||{})() }
-//~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple
-// variants
+//~^ ERROR calls in constant functions
 
 const fn bad(input: fn()) {
     input()
-    //~^ ERROR function pointers are not allowed in const fn
+    //~^ ERROR function pointer
 }
 
 fn main() {
diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr
index d3e9ce3..500af0a 100644
--- a/src/test/ui/consts/issue-56164.stderr
+++ b/src/test/ui/consts/issue-56164.stderr
@@ -5,7 +5,7 @@
    |                  ^^^^^^^^
 
 error: function pointers are not allowed in const fn
-  --> $DIR/issue-56164.rs:8:5
+  --> $DIR/issue-56164.rs:7:5
    |
 LL |     input()
    |     ^^^^^^^
diff --git a/src/test/ui/consts/issue-77062-large-zst-array.rs b/src/test/ui/consts/issue-77062-large-zst-array.rs
new file mode 100644
index 0000000..0566b80
--- /dev/null
+++ b/src/test/ui/consts/issue-77062-large-zst-array.rs
@@ -0,0 +1,5 @@
+// build-pass
+
+fn main() {
+    let _ = &[(); usize::MAX];
+}
diff --git a/src/test/ui/consts/min_const_fn/address_of.rs b/src/test/ui/consts/min_const_fn/address_of.rs
index f8506d7..40d1882 100644
--- a/src/test/ui/consts/min_const_fn/address_of.rs
+++ b/src/test/ui/consts/min_const_fn/address_of.rs
@@ -2,7 +2,7 @@
 
 const fn mutable_address_of_in_const() {
     let mut a = 0;
-    let b = &raw mut a;         //~ ERROR `&raw mut` is not allowed
+    let b = &raw mut a;         //~ ERROR mutable reference
 }
 
 struct X;
@@ -10,7 +10,7 @@
 impl X {
     const fn inherent_mutable_address_of_in_const() {
         let mut a = 0;
-        let b = &raw mut a;     //~ ERROR `&raw mut` is not allowed
+        let b = &raw mut a;     //~ ERROR mutable reference
     }
 }
 
diff --git a/src/test/ui/consts/min_const_fn/address_of.stderr b/src/test/ui/consts/min_const_fn/address_of.stderr
index 4d9d1d7..facc566 100644
--- a/src/test/ui/consts/min_const_fn/address_of.stderr
+++ b/src/test/ui/consts/min_const_fn/address_of.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `&raw mut` is not allowed in constant functions
+error[E0658]: raw mutable references are not allowed in constant functions
   --> $DIR/address_of.rs:5:13
    |
 LL |     let b = &raw mut a;
@@ -7,7 +7,7 @@
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: `&raw mut` is not allowed in constant functions
+error[E0658]: raw mutable references are not allowed in constant functions
   --> $DIR/address_of.rs:13:17
    |
 LL |         let b = &raw mut a;
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
index 937aae1..dc10db1 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
@@ -1,12 +1,14 @@
-#![feature(rustc_attrs, staged_api)]
+#![feature(rustc_attrs, staged_api, allow_internal_unstable)]
+#![feature(const_fn_fn_ptr_basics)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
-const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable
+const fn error(_: fn()) {}
+//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_allow_const_fn_ptr]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
+#[allow_internal_unstable(const_fn_fn_ptr_basics)]
 const fn compiles(_: fn()) {}
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
index 9a14bcc..a08d57b 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
@@ -1,12 +1,17 @@
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/allow_const_fn_ptr.rs:5:16
+error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
+  --> $DIR/allow_const_fn_ptr.rs:6:16
    |
 LL | const fn error(_: fn()) {}
    |                ^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+help: if it is not part of the public API, make this function unstably const
+   |
+LL | #[rustc_const_unstable(feature = "...", issue = "...")]
+   |
+help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
+   |
+LL | #[allow_internal_unstable(const_fn_fn_ptr_basics)]
+   |
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs
deleted file mode 100644
index 0f9d372..0000000
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(staged_api)]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-const fn error(_: fn()) {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_allow_const_fn_ptr]
-//~^ ERROR internal implementation detail
-const fn compiles(_: fn()) {}
-
-fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr
deleted file mode 100644
index 7794cc7..0000000
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: internal implementation detail
-  --> $DIR/allow_const_fn_ptr_feature_gate.rs:7:1
-   |
-LL | #[rustc_allow_const_fn_ptr]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
index 7aa9bd7..b4e836b 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
@@ -1,11 +1,13 @@
 // run-pass
+#![feature(allow_internal_unstable)]
+#![feature(const_fn_fn_ptr_basics)]
 
 #![feature(rustc_attrs, staged_api)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_allow_const_fn_ptr]
 #[rustc_const_stable(since="1.0.0", feature = "mep")]
+#[allow_internal_unstable(const_fn_fn_ptr_basics)]
 const fn takes_fn_ptr(_: fn()) {}
 
 const FN: fn() = || ();
diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
index 5890858..4e1b7bf 100644
--- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
+++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
@@ -1,7 +1,6 @@
 const fn foo(a: i32) -> Vec<i32> {
     vec![1, 2, 3]
     //~^ ERROR allocations are not allowed
-    //~| ERROR unimplemented expression type
     //~| ERROR calls in constant functions
 }
 
diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
index 0f16890..23697a8 100644
--- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
+++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
@@ -6,15 +6,6 @@
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0019]: constant function contains unimplemented expression type
-  --> $DIR/bad_const_fn_body_ice.rs:2:5
-   |
-LL |     vec![1, 2, 3]
-   |     ^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
   --> $DIR/bad_const_fn_body_ice.rs:2:5
    |
@@ -23,7 +14,7 @@
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0010, E0015, E0019.
+Some errors have detailed explanations: E0010, E0015.
 For more information about an error, try `rustc --explain E0010`.
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs
index 8d730df..b68f47f 100644
--- a/src/test/ui/consts/min_const_fn/cast_errors.rs
+++ b/src/test/ui/consts/min_const_fn/cast_errors.rs
@@ -2,12 +2,16 @@
 
 const fn unsize(x: &[u8; 3]) -> &[u8] { x }
 const fn closure() -> fn() { || {} }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
+//~| ERROR function pointer cast
 const fn closure2() {
     (|| {}) as fn();
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
 }
 const fn reify(f: fn()) -> unsafe fn() { f }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
+//~| ERROR function pointer
+//~| ERROR function pointer cast
 const fn reify2() { main as unsafe fn(); }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
+//~| ERROR function pointer cast
diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr
index 583cb4e..fb962bd 100644
--- a/src/test/ui/consts/min_const_fn/cast_errors.stderr
+++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr
@@ -1,39 +1,75 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/cast_errors.rs:4:23
    |
 LL | const fn closure() -> fn() { || {} }
    |                       ^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/cast_errors.rs:7:5
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/cast_errors.rs:4:30
    |
-LL |     (|| {}) as fn();
-   |     ^^^^^^^^^^^^^^^
+LL | const fn closure() -> fn() { || {} }
+   |                              ^^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/cast_errors.rs:10:28
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/cast_errors.rs:8:5
+   |
+LL |     (|| {}) as fn();
+   |     ^^^^^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
+
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/cast_errors.rs:11:16
+   |
+LL | const fn reify(f: fn()) -> unsafe fn() { f }
+   |                ^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
+
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/cast_errors.rs:11:28
    |
 LL | const fn reify(f: fn()) -> unsafe fn() { f }
    |                            ^^^^^^^^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/cast_errors.rs:12:21
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/cast_errors.rs:11:42
    |
-LL | const fn reify2() { main as unsafe fn(); }
-   |                     ^^^^^^^^^^^^^^^^^^^
+LL | const fn reify(f: fn()) -> unsafe fn() { f }
+   |                                          ^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error: aborting due to 4 previous errors
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/cast_errors.rs:15:21
+   |
+LL | const fn reify2() { main as unsafe fn(); }
+   |                     ^^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-For more information about this error, try `rustc --explain E0723`.
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/cast_errors.rs:15:21
+   |
+LL | const fn reify2() { main as unsafe fn(); }
+   |                     ^^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
index c2600f8..638ff1d 100644
--- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
+++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
@@ -1,5 +1,8 @@
-const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable
+const fn cmp(x: fn(), y: fn()) -> bool {
+    //~^ ERROR function pointer
+    //~| ERROR function pointer
     unsafe { x == y }
+    //~^ ERROR pointers cannot be reliably compared
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
index 74e5228..04c2feb 100644
--- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
+++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
@@ -1,12 +1,29 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/cmp_fn_pointers.rs:1:14
    |
 LL | const fn cmp(x: fn(), y: fn()) -> bool {
    |              ^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/cmp_fn_pointers.rs:1:23
+   |
+LL | const fn cmp(x: fn(), y: fn()) -> bool {
+   |                       ^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-For more information about this error, try `rustc --explain E0723`.
+error: pointers cannot be reliably compared during const eval.
+  --> $DIR/cmp_fn_pointers.rs:4:14
+   |
+LL |     unsafe { x == y }
+   |              ^^^^^^
+   |
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index 55a999d..e46127c 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -38,6 +38,8 @@
     const fn get(&self) -> &T { &self.0 }
     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
     //~^ mutable references
+    //~| mutable references
+    //~| mutable references
 }
 impl<'a, T> Foo<T> {
     const fn new_lt(t: T) -> Self { Foo(t) }
@@ -45,6 +47,8 @@
     const fn get_lt(&'a self) -> &T { &self.0 }
     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
     //~^ mutable references
+    //~| mutable references
+    //~| mutable references
 }
 impl<T: Sized> Foo<T> {
     const fn new_s(t: T) -> Self { Foo(t) }
@@ -52,11 +56,15 @@
     const fn get_s(&self) -> &T { &self.0 }
     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
     //~^ mutable references
+    //~| mutable references
+    //~| mutable references
 }
 impl<T: ?Sized> Foo<T> {
     const fn get_sq(&self) -> &T { &self.0 }
     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
     //~^ mutable references
+    //~| mutable references
+    //~| mutable references
 }
 
 
@@ -117,17 +125,24 @@
 struct AlanTuring<T>(T);
 const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
 //~^ ERROR trait bounds other than `Sized`
-const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
-const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+//~| ERROR destructor
+const fn no_apit(_x: impl std::fmt::Debug) {}
+//~^ ERROR trait bounds other than `Sized`
+//~| ERROR destructor
+const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
+//~^ ERROR trait bounds other than `Sized`
 const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
 //~^ ERROR trait bounds other than `Sized`
+//~| ERROR unsizing cast
+//~| ERROR unsizing cast
 
 const fn no_unsafe() { unsafe {} }
 
 const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR trait bounds other than `Sized`
+//~^ ERROR unsizing cast
 
 const fn no_fn_ptrs(_x: fn()) {}
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
 const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-//~^ ERROR function pointers in const fn are unstable
+//~^ ERROR function pointer
+//~| ERROR function pointer cast
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index a37e520..ee5434b 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -7,6 +7,15 @@
    |                         constant functions cannot evaluate destructors
 
 error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:39:22
+   |
+LL |     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+   |                      ^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/min_const_fn.rs:39:36
    |
 LL |     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
@@ -15,8 +24,17 @@
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:39:45
+   |
+LL |     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+   |                                             ^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/min_const_fn.rs:44:28
+  --> $DIR/min_const_fn.rs:46:28
    |
 LL |     const fn into_inner_lt(self) -> T { self.0 }
    |                            ^^^^                - value is dropped here
@@ -24,7 +42,16 @@
    |                            constant functions cannot evaluate destructors
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:46:42
+  --> $DIR/min_const_fn.rs:48:25
+   |
+LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+   |                         ^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:48:42
    |
 LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
    |                                          ^^^^^^
@@ -32,8 +59,17 @@
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:48:51
+   |
+LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+   |                                                   ^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/min_const_fn.rs:51:27
+  --> $DIR/min_const_fn.rs:55:27
    |
 LL |     const fn into_inner_s(self) -> T { self.0 }
    |                           ^^^^                - value is dropped here
@@ -41,7 +77,16 @@
    |                           constant functions cannot evaluate destructors
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:53:38
+  --> $DIR/min_const_fn.rs:57:24
+   |
+LL |     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+   |                        ^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:57:38
    |
 LL |     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
    |                                      ^^^^^^
@@ -50,7 +95,25 @@
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:58:39
+  --> $DIR/min_const_fn.rs:57:47
+   |
+LL |     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+   |                                               ^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:64:25
+   |
+LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+   |                         ^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:64:39
    |
 LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
    |                                       ^^^^^^
@@ -58,8 +121,17 @@
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:64:48
+   |
+LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+   |                                                ^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:76:16
+  --> $DIR/min_const_fn.rs:84:16
    |
 LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
    |                ^
@@ -68,7 +140,7 @@
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:78:18
+  --> $DIR/min_const_fn.rs:86:18
    |
 LL | const fn foo11_2<T: Send>(t: T) -> T { t }
    |                  ^
@@ -77,7 +149,7 @@
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0013]: constant functions cannot refer to statics
-  --> $DIR/min_const_fn.rs:82:27
+  --> $DIR/min_const_fn.rs:90:27
    |
 LL | const fn foo25() -> u32 { BAR }
    |                           ^^^
@@ -85,7 +157,7 @@
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0013]: constant functions cannot refer to statics
-  --> $DIR/min_const_fn.rs:83:37
+  --> $DIR/min_const_fn.rs:91:37
    |
 LL | const fn foo26() -> &'static u32 { &BAR }
    |                                     ^^^
@@ -93,7 +165,7 @@
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
 error[E0658]: casting pointers to integers in constant functions is unstable
-  --> $DIR/min_const_fn.rs:84:42
+  --> $DIR/min_const_fn.rs:92:42
    |
 LL | const fn foo30(x: *const u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
@@ -102,7 +174,7 @@
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constant functions is unstable
-  --> $DIR/min_const_fn.rs:86:63
+  --> $DIR/min_const_fn.rs:94:63
    |
 LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
@@ -111,7 +183,7 @@
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constant functions is unstable
-  --> $DIR/min_const_fn.rs:88:42
+  --> $DIR/min_const_fn.rs:96:42
    |
 LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
    |                                          ^^^^^^^^^^
@@ -120,7 +192,7 @@
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constant functions is unstable
-  --> $DIR/min_const_fn.rs:90:63
+  --> $DIR/min_const_fn.rs:98:63
    |
 LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
    |                                                               ^^^^^^^^^^
@@ -129,7 +201,7 @@
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/min_const_fn.rs:93:14
+  --> $DIR/min_const_fn.rs:101:14
    |
 LL | const fn inc(x: &mut i32) { *x += 1 }
    |              ^
@@ -138,7 +210,7 @@
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:102:6
+  --> $DIR/min_const_fn.rs:110:6
    |
 LL | impl<T: std::fmt::Debug> Foo<T> {
    |      ^
@@ -147,7 +219,7 @@
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:107:6
+  --> $DIR/min_const_fn.rs:115:6
    |
 LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
    |      ^
@@ -156,7 +228,7 @@
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:112:6
+  --> $DIR/min_const_fn.rs:120:6
    |
 LL | impl<T: Sync + Sized> Foo<T> {
    |      ^
@@ -165,7 +237,7 @@
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:118:34
+  --> $DIR/min_const_fn.rs:126:34
    |
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                                  ^^^^^^^^^^^^^^^^^^^^
@@ -173,8 +245,16 @@
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:126:19
+   |
+LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+   |                   ^^                                     - value is dropped here
+   |                   |
+   |                   constant functions cannot evaluate destructors
+
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:120:22
+  --> $DIR/min_const_fn.rs:129:22
    |
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                      ^^^^^^^^^^^^^^^^^^^^
@@ -182,8 +262,16 @@
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:129:18
+   |
+LL | const fn no_apit(_x: impl std::fmt::Debug) {}
+   |                  ^^                         - value is dropped here
+   |                  |
+   |                  constant functions cannot evaluate destructors
+
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:121:23
+  --> $DIR/min_const_fn.rs:132:23
    |
 LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    |                       ^^
@@ -192,7 +280,7 @@
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:122:32
+  --> $DIR/min_const_fn.rs:134:32
    |
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -200,34 +288,61 @@
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
-  --> $DIR/min_const_fn.rs:127:41
+error[E0723]: unsizing casts to types besides slices are not allowed in const fn
+  --> $DIR/min_const_fn.rs:134:63
    |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+   |                                                               ^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:130:21
+error[E0723]: unsizing casts to types besides slices are not allowed in const fn
+  --> $DIR/min_const_fn.rs:134:63
+   |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+   |                                                               ^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error[E0723]: unsizing casts to types besides slices are not allowed in const fn
+  --> $DIR/min_const_fn.rs:141:42
+   |
+LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
+   |                                          ^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/min_const_fn.rs:144:21
    |
 LL | const fn no_fn_ptrs(_x: fn()) {}
    |                     ^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn.rs:132:27
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/min_const_fn.rs:146:27
    |
 LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
    |                           ^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error: aborting due to 26 previous errors
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/min_const_fn.rs:146:46
+   |
+LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+   |                                              ^^^
+   |
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
+
+error: aborting due to 39 previous errors
 
 Some errors have detailed explanations: E0013, E0493, E0658, E0723.
 For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
index 6ca1e59..4a22ef2 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
@@ -10,6 +10,6 @@
 //~^ ERROR trait bounds other than `Sized`
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR trait bounds other than `Sized`
+//~^ ERROR unsizing cast
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
index 17e171c..1394db5 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
@@ -7,7 +7,7 @@
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
-error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+error[E0723]: unsizing casts to types besides slices are not allowed in const fn
   --> $DIR/min_const_fn_dyn.rs:12:66
    |
 LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
index 584ea46..bc6fe89 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs
@@ -1,3 +1,5 @@
+// gate-test-const_fn_fn_ptr_basics
+
 struct HasPtr {
     field: fn(),
 }
@@ -9,9 +11,9 @@
 const fn no_inner_dyn_trait(_x: Hide) {}
 const fn no_inner_dyn_trait2(x: Hide) {
     x.0.field;
-//~^ ERROR function pointers in const fn
+//~^ ERROR function pointer
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-//~^ ERROR function pointers in const fn
+//~^ ERROR function pointer
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
index 58acbb5..8d82674 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr
@@ -1,21 +1,21 @@
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn_fn_ptr.rs:11:5
+error[E0658]: function pointers cannot appear in constant functions
+  --> $DIR/min_const_fn_fn_ptr.rs:13:5
    |
 LL |     x.0.field;
    |     ^^^^^^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
-error[E0723]: function pointers in const fn are unstable
-  --> $DIR/min_const_fn_fn_ptr.rs:14:59
+error[E0658]: function pointer casts are not allowed in constant functions
+  --> $DIR/min_const_fn_fn_ptr.rs:16:59
    |
 LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
    |                                                           ^^^^^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
index 9cc9b69..e062c9f 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
@@ -1,9 +1,10 @@
+// gate-test-const_impl_trait
+
 struct AlanTuring<T>(T);
-const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
-    //~^ ERROR `impl Trait` in const fn is unstable
+const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { //~ `impl Trait`
     AlanTuring(0)
 }
 
-const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+const fn no_rpit() -> impl std::fmt::Debug {} //~ `impl Trait`
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
index a62a340..01c797c 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
@@ -1,21 +1,21 @@
-error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn_impl_trait.rs:2:24
+error[E0658]: `impl Trait` is not allowed in constant functions
+  --> $DIR/min_const_fn_impl_trait.rs:4:24
    |
 LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
+   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
 
-error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn_impl_trait.rs:7:23
+error[E0658]: `impl Trait` is not allowed in constant functions
+  --> $DIR/min_const_fn_impl_trait.rs:8:23
    |
 LL | const fn no_rpit() -> impl std::fmt::Debug {}
    |                       ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
+   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index fa2260b..de6a9a1 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -20,11 +20,14 @@
 LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                          ^^^^^^^^^^^^^
    |
-   = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
 help: if it is not part of the public API, make this function unstably const
    |
 LL | #[rustc_const_unstable(feature = "...", issue = "...")]
    |
+help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
+   |
+LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)]
+   |
 
 error: `foo2_gated` is not yet stable as a const fn
   --> $DIR/min_const_fn_libstd_stability.rs:39:32
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index 1ca5964..f258deb 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -20,11 +20,14 @@
 LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                                 ^^^^^^^^^^^^^
    |
-   = note: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
 help: if it is not part of the public API, make this function unstably const
    |
 LL | #[rustc_const_unstable(feature = "...", issue = "...")]
    |
+help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks
+   |
+LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)]
+   |
 
 error: `foo2_gated` is not yet stable as a const fn
   --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48
diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr
index 4e5cdbb..8e95a4c 100644
--- a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr
+++ b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr
@@ -1,17 +1,17 @@
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/mutable_borrow.rs:3:9
+  --> $DIR/mutable_borrow.rs:3:13
    |
 LL |     let b = &mut a;
-   |         ^
+   |             ^^^^^^
    |
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/mutable_borrow.rs:12:13
+  --> $DIR/mutable_borrow.rs:12:17
    |
 LL |         let b = &mut a;
-   |             ^
+   |                 ^^^^^^
    |
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
index 93b67fd..8fd562c 100644
--- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
+++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr
@@ -12,12 +12,12 @@
 
 warning: skipping const checks
    |
-help: skipping check for `const_fn` feature
+help: skipping check for `const_fn_fn_ptr_basics` feature
   --> $DIR/abi-mismatch.rs:9:23
    |
 LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) {
    |                       ^^^^^
-help: skipping check for `const_fn` feature
+help: skipping check for `const_fn_fn_ptr_basics` feature
   --> $DIR/abi-mismatch.rs:10:5
    |
 LL |     my_fn();
diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs
index 7db970c..5e2584a 100644
--- a/src/test/ui/consts/projection_qualif.rs
+++ b/src/test/ui/consts/projection_qualif.rs
@@ -9,7 +9,6 @@
     {
         let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants
         unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
-        //[stock]~^ contains unimplemented expression
     }
     &{a}
 };
diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr
index 212f122..fad8f01 100644
--- a/src/test/ui/consts/projection_qualif.stock.stderr
+++ b/src/test/ui/consts/projection_qualif.stock.stderr
@@ -13,15 +13,7 @@
    = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
    = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/projection_qualif.rs:11:18
-   |
-LL |         unsafe { *b = 5; }
-   |                  ^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+error: aborting due to 2 previous errors
 
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0019, E0658, E0764.
-For more information about an error, try `rustc --explain E0019`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
index a6bbe8d..2821d1a 100644
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
@@ -6,6 +6,5 @@
 
 pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
 //~^ ERROR  mutable references are not allowed in statics
-//[stock]~| ERROR static contains unimplemented expression type
 
 fn main() {}
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
index 57fb27e..36c280c 100644
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
@@ -4,15 +4,6 @@
 LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/static_mut_containing_mut_ref2.rs:7:45
-   |
-LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0019, E0764.
-For more information about an error, try `rustc --explain E0019`.
+For more information about this error, try `rustc --explain E0764`.
diff --git a/src/test/ui/consts/trait_specialization.stderr b/src/test/ui/consts/trait_specialization.stderr
index 03da7d5..e80821c 100644
--- a/src/test/ui/consts/trait_specialization.stderr
+++ b/src/test/ui/consts/trait_specialization.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/consts/unwind-abort.rs b/src/test/ui/consts/unwind-abort.rs
new file mode 100644
index 0000000..f9011f9
--- /dev/null
+++ b/src/test/ui/consts/unwind-abort.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+#![feature(unwind_attributes, const_panic)]
+
+// `#[unwind(aborts)]` is okay for a `const fn`. We don't unwind in const-eval anyways.
+#[unwind(aborts)]
+const fn foo() {
+    panic!()
+}
+
+const fn bar() {
+    foo();
+}
+
+fn main() {
+    bar();
+}
diff --git a/src/test/ui/deref-lval.rs b/src/test/ui/deref-lval.rs
deleted file mode 100644
index f57872f..0000000
--- a/src/test/ui/deref-lval.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// run-pass
-
-#![feature(box_syntax)]
-
-use std::cell::Cell;
-
-pub fn main() {
-    let x: Box<_> = box Cell::new(5);
-    x.set(1000);
-    println!("{}", x.get());
-}
diff --git a/src/test/ui/deriving/deriving-associated-types.rs b/src/test/ui/deriving/deriving-associated-types.rs
index 4b1cbe8..13735ff 100644
--- a/src/test/ui/deriving/deriving-associated-types.rs
+++ b/src/test/ui/deriving/deriving-associated-types.rs
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-compare-mode-chalk
 pub trait DeclaredTrait {
     type Type;
 }
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs
index e66b432..99ebe84 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs
@@ -68,7 +68,6 @@
 
 union O<F> where F: Fn() -> _ {
 //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
-//~| ERROR unions with non-`Copy` fields are unstable
     foo: F,
 }
 
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
index 4835d9a..ebc0883 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
@@ -57,19 +57,6 @@
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0658]: unions with non-`Copy` fields are unstable
-  --> $DIR/bad-assoc-ty.rs:69:1
-   |
-LL | / union O<F> where F: Fn() -> _ {
-LL | |
-LL | |
-LL | |     foo: F,
-LL | | }
-   | |_^
-   |
-   = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
-   = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
-
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:1:10
    |
@@ -215,7 +202,7 @@
    |          ^^^                   ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/bad-assoc-ty.rs:75:29
+  --> $DIR/bad-assoc-ty.rs:74:29
    |
 LL | trait P<F> where F: Fn() -> _ {
    |                             ^ not allowed in type signatures
@@ -226,7 +213,7 @@
    |          ^^^                   ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/bad-assoc-ty.rs:80:38
+  --> $DIR/bad-assoc-ty.rs:79:38
    |
 LL |     fn foo<F>(_: F) where F: Fn() -> _ {}
    |                                      ^ not allowed in type signatures
@@ -236,7 +223,7 @@
 LL |     fn foo<F, T>(_: F) where F: Fn() -> T {}
    |             ^^^                         ^
 
-error: aborting due to 29 previous errors
+error: aborting due to 28 previous errors
 
-Some errors have detailed explanations: E0121, E0223, E0658.
+Some errors have detailed explanations: E0121, E0223.
 For more information about an error, try `rustc --explain E0121`.
diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
index 2140fd3..bca493e 100644
--- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
+++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
@@ -2,46 +2,43 @@
   --> $DIR/issue-43871-enum-instead-of-variant.rs:19:13
    |
 LL |     let x = Option(1);
-   |             ^^^^^^
+   |             ^^^^^^ help: try to construct one of the enum's variants: `std::option::Option::Some`
    |
-help: try using one of the enum's variants
-   |
-LL |     let x = std::option::Option::None(1);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     let x = std::option::Option::Some(1);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: you might have meant to construct the enum's non-tuple variant
 
 error[E0532]: expected tuple struct or tuple variant, found enum `Option`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12
    |
 LL |     if let Option(_) = x {
-   |            ^^^^^^
+   |            ^^^^^^ help: try to match against one of the enum's variants: `std::option::Option::Some`
    |
-help: try using one of the enum's variants
-   |
-LL |     if let std::option::Option::None(_) = x {
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     if let std::option::Option::Some(_) = x {
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: you might have meant to match against the enum's non-tuple variant
 
 error[E0532]: expected tuple struct or tuple variant, found enum `Example`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12
    |
 LL |     if let Example(_) = y {
-   |            ^^^^^^^
+   |            ^^^^^^^ help: try to match against one of the enum's variants: `Example::Ex`
    |
-help: try using one of the enum's variants
+   = help: you might have meant to match against the enum's non-tuple variant
+note: the enum is defined here
+  --> $DIR/issue-43871-enum-instead-of-variant.rs:1:1
    |
-LL |     if let Example::Ex(_) = y {
-   |            ^^^^^^^^^^^
-LL |     if let Example::NotEx(_) = y {
-   |            ^^^^^^^^^^^^^^
+LL | enum Example { Ex(String), NotEx }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0423]: expected function, tuple struct or tuple variant, found enum `Void`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:31:13
    |
 LL |     let y = Void();
    |             ^^^^
+   |
+   = help: the enum has no tuple variants to construct
+note: the enum is defined here
+  --> $DIR/issue-43871-enum-instead-of-variant.rs:3:1
+   |
+LL | enum Void {}
+   | ^^^^^^^^^^^^
 
 error[E0423]: expected function, tuple struct or tuple variant, found enum `ManyVariants`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:33:13
@@ -49,17 +46,19 @@
 LL |     let z = ManyVariants();
    |             ^^^^^^^^^^^^
    |
-help: try using one of the enum's variants
+   = help: the enum has no tuple variants to construct
+   = help: you might have meant to construct one of the enum's non-tuple variants
+note: the enum is defined here
+  --> $DIR/issue-43871-enum-instead-of-variant.rs:5:1
    |
-LL |     let z = ManyVariants::One();
-   |             ^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Two();
-   |             ^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Three();
-   |             ^^^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Four();
-   |             ^^^^^^^^^^^^^^^^^^
-     and 6 other candidates
+LL | / enum ManyVariants {
+LL | |     One,
+LL | |     Two,
+LL | |     Three,
+...  |
+LL | |     Ten,
+LL | | }
+   | |_^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
index a8b160b..68734cd 100644
--- a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
+++ b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
@@ -14,9 +14,10 @@
   --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
    |
 LL |     let _: &Copy + 'static;
-   |            ^^^^^ the trait `Copy` cannot be made into an object
+   |            ^^^^^ `Copy` cannot be made into an object
    |
    = note: the trait cannot be made into an object because it requires `Self: Sized`
+   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/doc-alias-crate-level.rs b/src/test/ui/doc-alias-crate-level.rs
new file mode 100644
index 0000000..b1b17f2
--- /dev/null
+++ b/src/test/ui/doc-alias-crate-level.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Zdeduplicate-diagnostics=no
+
+#![feature(doc_alias)]
+
+#![crate_type = "lib"]
+
+#![doc(alias = "shouldn't work!")] //~ ERROR
diff --git a/src/test/ui/doc-alias-crate-level.stderr b/src/test/ui/doc-alias-crate-level.stderr
new file mode 100644
index 0000000..45756d6
--- /dev/null
+++ b/src/test/ui/doc-alias-crate-level.stderr
@@ -0,0 +1,8 @@
+error: '\'' character isn't allowed in `#[doc(alias = "...")]`
+  --> $DIR/doc-alias-crate-level.rs:7:8
+   |
+LL | #![doc(alias = "shouldn't work!")]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs b/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs
new file mode 100644
index 0000000..063efc7
--- /dev/null
+++ b/src/test/ui/drop-bounds/drop-bounds-impl-drop.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![deny(drop_bounds)]
+// As a special exemption, `impl Drop` in the return position raises no error.
+// This allows a convenient way to return an unnamed drop guard.
+fn voldemort_type() -> impl Drop {
+  struct Voldemort;
+  impl Drop for Voldemort {
+    fn drop(&mut self) {}
+  }
+  Voldemort
+}
+fn main() {
+  let _ = voldemort_type();
+}
diff --git a/src/test/ui/drop-bounds/drop-bounds.rs b/src/test/ui/drop-bounds/drop-bounds.rs
new file mode 100644
index 0000000..c735382
--- /dev/null
+++ b/src/test/ui/drop-bounds/drop-bounds.rs
@@ -0,0 +1,19 @@
+#![deny(drop_bounds)]
+fn foo<T: Drop>() {} //~ ERROR
+fn bar<U>()
+where
+    U: Drop, //~ ERROR
+{
+}
+fn baz(_x: impl Drop) {} //~ ERROR
+struct Foo<T: Drop> { //~ ERROR
+  _x: T
+}
+struct Bar<U> where U: Drop { //~ ERROR
+  _x: U
+}
+trait Baz: Drop { //~ ERROR
+}
+impl<T: Drop> Baz for T { //~ ERROR
+}
+fn main() {}
diff --git a/src/test/ui/drop-bounds/drop-bounds.stderr b/src/test/ui/drop-bounds/drop-bounds.stderr
new file mode 100644
index 0000000..15ba4c9
--- /dev/null
+++ b/src/test/ui/drop-bounds/drop-bounds.stderr
@@ -0,0 +1,50 @@
+error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:2:11
+   |
+LL | fn foo<T: Drop>() {}
+   |           ^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/drop-bounds.rs:1:9
+   |
+LL | #![deny(drop_bounds)]
+   |         ^^^^^^^^^^^
+
+error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:5:8
+   |
+LL |     U: Drop,
+   |        ^^^^
+
+error: bounds on `impl Drop: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:8:17
+   |
+LL | fn baz(_x: impl Drop) {}
+   |                 ^^^^
+
+error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:9:15
+   |
+LL | struct Foo<T: Drop> {
+   |               ^^^^
+
+error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:12:24
+   |
+LL | struct Bar<U> where U: Drop {
+   |                        ^^^^
+
+error: bounds on `Self: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:15:12
+   |
+LL | trait Baz: Drop {
+   |            ^^^^
+
+error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
+  --> $DIR/drop-bounds.rs:17:9
+   |
+LL | impl<T: Drop> Baz for T {
+   |         ^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs
index 88d36ab..b027faa 100644
--- a/src/test/ui/drop/dynamic-drop-async.rs
+++ b/src/test/ui/drop/dynamic-drop-async.rs
@@ -7,8 +7,6 @@
 // edition:2018
 // ignore-wasm32-bare compiled with panic=abort by default
 
-#![feature(move_ref_pattern)]
-
 #![allow(unused)]
 
 use std::{
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index d31736f..6d0cd10 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -1,8 +1,7 @@
 // run-pass
 // ignore-wasm32-bare compiled with panic=abort by default
 
-#![feature(generators, generator_trait, untagged_unions)]
-#![feature(move_ref_pattern)]
+#![feature(generators, generator_trait)]
 #![feature(bindings_after_at)]
 
 #![allow(unused_assignments)]
diff --git a/src/test/ui/dropck/dropck-union.rs b/src/test/ui/dropck/dropck-union.rs
index ef4d1b3..5a9965d 100644
--- a/src/test/ui/dropck/dropck-union.rs
+++ b/src/test/ui/dropck/dropck-union.rs
@@ -1,5 +1,3 @@
-#![feature(untagged_unions)]
-
 use std::cell::Cell;
 use std::ops::Deref;
 use std::mem::ManuallyDrop;
diff --git a/src/test/ui/dropck/dropck-union.stderr b/src/test/ui/dropck/dropck-union.stderr
index 2287443..854e293 100644
--- a/src/test/ui/dropck/dropck-union.stderr
+++ b/src/test/ui/dropck/dropck-union.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `v` does not live long enough
-  --> $DIR/dropck-union.rs:39:18
+  --> $DIR/dropck-union.rs:37:18
    |
 LL |     v.0.set(Some(&v));
    |                  ^^ borrowed value does not live long enough
diff --git a/src/test/ui/empty/empty-macro-use.stderr b/src/test/ui/empty/empty-macro-use.stderr
index 8e3e068..700f661 100644
--- a/src/test/ui/empty/empty-macro-use.stderr
+++ b/src/test/ui/empty/empty-macro-use.stderr
@@ -3,6 +3,9 @@
    |
 LL |     macro_two!();
    |     ^^^^^^^^^
+   |
+   = note: consider importing this macro:
+           two_macros::macro_two
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/enum-discriminant/discriminant_size.rs b/src/test/ui/enum-discriminant/discriminant_size.rs
index 4cede8c..b939a70 100644
--- a/src/test/ui/enum-discriminant/discriminant_size.rs
+++ b/src/test/ui/enum-discriminant/discriminant_size.rs
@@ -1,5 +1,6 @@
 // run-pass
 #![feature(core_intrinsics, repr128)]
+//~^ WARN the feature `repr128` is incomplete
 
 use std::intrinsics::discriminant_value;
 
diff --git a/src/test/ui/enum-discriminant/discriminant_size.stderr b/src/test/ui/enum-discriminant/discriminant_size.stderr
new file mode 100644
index 0000000..efc7d99
--- /dev/null
+++ b/src/test/ui/enum-discriminant/discriminant_size.stderr
@@ -0,0 +1,11 @@
+warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/discriminant_size.rs:2:29
+   |
+LL | #![feature(core_intrinsics, repr128)]
+   |                             ^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #56071 <https://github.com/rust-lang/rust/issues/56071> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
index 4e2cc89..ae389e1 100644
--- a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
+++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
@@ -1,5 +1,6 @@
 // run-pass
 #![feature(repr128, arbitrary_enum_discriminant)]
+//~^ WARN the feature `repr128` is incomplete
 
 #[derive(PartialEq, Debug)]
 #[repr(i128)]
diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr b/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr
new file mode 100644
index 0000000..5bf6ea5
--- /dev/null
+++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr
@@ -0,0 +1,11 @@
+warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-70509-partial_eq.rs:2:12
+   |
+LL | #![feature(repr128, arbitrary_enum_discriminant)]
+   |            ^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #56071 <https://github.com/rust-lang/rust/issues/56071> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/enum-discriminant/repr128.rs b/src/test/ui/enum-discriminant/repr128.rs
index eefbc44..00021a0 100644
--- a/src/test/ui/enum-discriminant/repr128.rs
+++ b/src/test/ui/enum-discriminant/repr128.rs
@@ -1,5 +1,6 @@
 // run-pass
 #![feature(repr128, core_intrinsics, discriminant_kind)]
+//~^ WARN the feature `repr128` is incomplete
 
 use std::intrinsics::discriminant_value;
 use std::marker::DiscriminantKind;
diff --git a/src/test/ui/enum-discriminant/repr128.stderr b/src/test/ui/enum-discriminant/repr128.stderr
new file mode 100644
index 0000000..88adfb1
--- /dev/null
+++ b/src/test/ui/enum-discriminant/repr128.stderr
@@ -0,0 +1,11 @@
+warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/repr128.rs:2:12
+   |
+LL | #![feature(repr128, core_intrinsics, discriminant_kind)]
+   |            ^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #56071 <https://github.com/rust-lang/rust/issues/56071> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/error-codes/E0007.rs b/src/test/ui/error-codes/E0007.rs
deleted file mode 100644
index 022ac5f..0000000
--- a/src/test/ui/error-codes/E0007.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(bindings_after_at)]
-
-fn main() {
-    let x = Some("s".to_string());
-    match x {
-        op_string @ Some(s) => {},
-        //~^ ERROR E0007
-        //~| ERROR E0382
-        None => {},
-    }
-}
diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr
deleted file mode 100644
index 89c1051..0000000
--- a/src/test/ui/error-codes/E0007.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0007]: cannot bind by-move with sub-bindings
-  --> $DIR/E0007.rs:6:9
-   |
-LL |         op_string @ Some(s) => {},
-   |         ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
-
-error[E0382]: use of moved value
-  --> $DIR/E0007.rs:6:26
-   |
-LL |     let x = Some("s".to_string());
-   |         - move occurs because `x` has type `Option<String>`, which does not implement the `Copy` trait
-LL |     match x {
-LL |         op_string @ Some(s) => {},
-   |         -----------------^-
-   |         |                |
-   |         |                value used here after move
-   |         value moved here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0007, E0382.
-For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/error-codes/E0010-teach.rs b/src/test/ui/error-codes/E0010-teach.rs
index da51035..fc5dffb 100644
--- a/src/test/ui/error-codes/E0010-teach.rs
+++ b/src/test/ui/error-codes/E0010-teach.rs
@@ -4,6 +4,5 @@
 #![allow(warnings)]
 
 const CON : Box<i32> = box 0; //~ ERROR E0010
-//~^ ERROR constant contains unimplemented expression type
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0010-teach.stderr b/src/test/ui/error-codes/E0010-teach.stderr
index c15ab5c..33de9fd 100644
--- a/src/test/ui/error-codes/E0010-teach.stderr
+++ b/src/test/ui/error-codes/E0010-teach.stderr
@@ -6,17 +6,6 @@
    |
    = note: The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time.
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/E0010-teach.rs:6:28
-   |
-LL | const CON : Box<i32> = box 0;
-   |                            ^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-   = note: A function call isn't allowed in the const's initialization expression because the expression's value must be known at compile-time.
-   = note: Remember: you can't use a function call inside a const's initialization expression! However, you can use it anywhere else.
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0010, E0019.
-For more information about an error, try `rustc --explain E0010`.
+For more information about this error, try `rustc --explain E0010`.
diff --git a/src/test/ui/error-codes/E0010.rs b/src/test/ui/error-codes/E0010.rs
index 3398e2c..e629976 100644
--- a/src/test/ui/error-codes/E0010.rs
+++ b/src/test/ui/error-codes/E0010.rs
@@ -2,6 +2,5 @@
 #![allow(warnings)]
 
 const CON : Box<i32> = box 0; //~ ERROR E0010
-//~^ ERROR constant contains unimplemented expression type
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0010.stderr b/src/test/ui/error-codes/E0010.stderr
index f49fb9c..0042333 100644
--- a/src/test/ui/error-codes/E0010.stderr
+++ b/src/test/ui/error-codes/E0010.stderr
@@ -4,15 +4,6 @@
 LL | const CON : Box<i32> = box 0;
    |                        ^^^^^ allocation not allowed in constants
 
-error[E0019]: constant contains unimplemented expression type
-  --> $DIR/E0010.rs:4:28
-   |
-LL | const CON : Box<i32> = box 0;
-   |                            ^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0010, E0019.
-For more information about an error, try `rustc --explain E0010`.
+For more information about this error, try `rustc --explain E0010`.
diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs
index 54d3cc5..262f7bc 100644
--- a/src/test/ui/error-codes/E0017.rs
+++ b/src/test/ui/error-codes/E0017.rs
@@ -5,8 +5,8 @@
 const CR: &'static mut i32 = &mut C; //~ ERROR E0764
                                      //~| WARN taking a mutable
 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764
-                                              //~| ERROR E0019
                                               //~| ERROR cannot borrow
+
 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
                                               //~| WARN taking a mutable
 static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764
diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr
index 40ef6bd..ea59158 100644
--- a/src/test/ui/error-codes/E0017.stderr
+++ b/src/test/ui/error-codes/E0017.stderr
@@ -19,14 +19,6 @@
 LL | const CR: &'static mut i32 = &mut C;
    |                              ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/E0017.rs:7:39
-   |
-LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0017.rs:7:39
    |
@@ -65,7 +57,7 @@
 LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
    |                                                    ^^^^^^ `&mut` is only allowed in `const fn`
 
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 5 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0019, E0596, E0764.
-For more information about an error, try `rustc --explain E0019`.
+Some errors have detailed explanations: E0596, E0764.
+For more information about an error, try `rustc --explain E0596`.
diff --git a/src/test/ui/error-codes/E0029-teach.rs b/src/test/ui/error-codes/E0029-teach.rs
index 83058d3..3ff8cb3 100644
--- a/src/test/ui/error-codes/E0029-teach.rs
+++ b/src/test/ui/error-codes/E0029-teach.rs
@@ -5,7 +5,7 @@
 
     match s {
         "hello" ..= "world" => {}
-        //~^ ERROR only char and numeric types are allowed in range patterns
+        //~^ ERROR only `char` and numeric types are allowed in range patterns
         _ => {}
     }
 }
diff --git a/src/test/ui/error-codes/E0029-teach.stderr b/src/test/ui/error-codes/E0029-teach.stderr
index ec146ca..b89b2e7 100644
--- a/src/test/ui/error-codes/E0029-teach.stderr
+++ b/src/test/ui/error-codes/E0029-teach.stderr
@@ -1,4 +1,4 @@
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/E0029-teach.rs:7:9
    |
 LL |         "hello" ..= "world" => {}
diff --git a/src/test/ui/error-codes/E0029.rs b/src/test/ui/error-codes/E0029.rs
index fe0d851..d9b53e1 100644
--- a/src/test/ui/error-codes/E0029.rs
+++ b/src/test/ui/error-codes/E0029.rs
@@ -3,7 +3,7 @@
 
     match s {
         "hello" ..= "world" => {}
-        //~^ ERROR only char and numeric types are allowed in range patterns
+        //~^ ERROR only `char` and numeric types are allowed in range patterns
         _ => {}
     }
 }
diff --git a/src/test/ui/error-codes/E0029.stderr b/src/test/ui/error-codes/E0029.stderr
index e54722a..f7250b3 100644
--- a/src/test/ui/error-codes/E0029.stderr
+++ b/src/test/ui/error-codes/E0029.stderr
@@ -1,4 +1,4 @@
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/E0029.rs:5:9
    |
 LL |         "hello" ..= "world" => {}
diff --git a/src/test/ui/error-codes/E0033-teach.stderr b/src/test/ui/error-codes/E0033-teach.stderr
index f323a99..513fda3 100644
--- a/src/test/ui/error-codes/E0033-teach.stderr
+++ b/src/test/ui/error-codes/E0033-teach.stderr
@@ -7,15 +7,21 @@
 error[E0038]: the trait `SomeTrait` cannot be made into an object
   --> $DIR/E0033-teach.rs:8:20
    |
+LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
+   |                    ^^^^^^^^^^^^^^ `SomeTrait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/E0033-teach.rs:4:8
+   |
 LL | trait SomeTrait {
    |       --------- this trait cannot be made into an object...
 LL |     fn foo();
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
-   |                    ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+help: consider turning `foo` into a method by giving it a `&self` argument
    |
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn foo(&self);
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() where Self: Sized;
    |              ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/error-codes/E0033.stderr b/src/test/ui/error-codes/E0033.stderr
index 84481ff..fc12484 100644
--- a/src/test/ui/error-codes/E0033.stderr
+++ b/src/test/ui/error-codes/E0033.stderr
@@ -7,15 +7,21 @@
 error[E0038]: the trait `SomeTrait` cannot be made into an object
   --> $DIR/E0033.rs:6:20
    |
+LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
+   |                    ^^^^^^^^^^^^^^ `SomeTrait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/E0033.rs:2:8
+   |
 LL | trait SomeTrait {
    |       --------- this trait cannot be made into an object...
 LL |     fn foo();
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL |     let trait_obj: &dyn SomeTrait = SomeTrait;
-   |                    ^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+help: consider turning `foo` into a method by giving it a `&self` argument
    |
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn foo(&self);
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() where Self: Sized;
    |              ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/error-codes/E0038.stderr b/src/test/ui/error-codes/E0038.stderr
index 638e924..eb68a62 100644
--- a/src/test/ui/error-codes/E0038.stderr
+++ b/src/test/ui/error-codes/E0038.stderr
@@ -1,15 +1,17 @@
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/E0038.rs:5:16
    |
+LL | fn call_foo(x: Box<dyn Trait>) {
+   |                ^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+   = help: consider moving `foo` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/E0038.rs:2:22
+   |
 LL | trait Trait {
    |       ----- this trait cannot be made into an object...
 LL |     fn foo(&self) -> Self;
-   |                      ---- ...because method `foo` references the `Self` type in its return type
-...
-LL | fn call_foo(x: Box<dyn Trait>) {
-   |                ^^^^^^^^^^^^^^ the trait `Trait` cannot be made into an object
-   |
-   = help: consider moving `foo` to another trait
+   |                      ^^^^ ...because method `foo` references the `Self` type in its return type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0060.stderr b/src/test/ui/error-codes/E0060.stderr
index a600592..c80014d 100644
--- a/src/test/ui/error-codes/E0060.stderr
+++ b/src/test/ui/error-codes/E0060.stderr
@@ -1,13 +1,16 @@
 error[E0060]: this function takes at least 1 argument but 0 arguments were supplied
   --> $DIR/E0060.rs:6:14
    |
-LL |     fn printf(_: *const u8, ...) -> u32;
-   |     ------------------------------------ defined here
-...
 LL |     unsafe { printf(); }
    |              ^^^^^^-- supplied 0 arguments
    |              |
    |              expected at least 1 argument
+   |
+note: function defined here
+  --> $DIR/E0060.rs:2:8
+   |
+LL |     fn printf(_: *const u8, ...) -> u32;
+   |        ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0061.stderr b/src/test/ui/error-codes/E0061.stderr
index dfefa0d..98488a2 100644
--- a/src/test/ui/error-codes/E0061.stderr
+++ b/src/test/ui/error-codes/E0061.stderr
@@ -1,24 +1,30 @@
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/E0061.rs:6:5
    |
-LL | fn f(a: u16, b: &str) {}
-   | --------------------- defined here
-...
 LL |     f(0);
    |     ^ - supplied 1 argument
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/E0061.rs:1:4
+   |
+LL | fn f(a: u16, b: &str) {}
+   |    ^ ------  -------
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/E0061.rs:10:5
    |
-LL | fn f2(a: u16) {}
-   | ------------- defined here
-...
 LL |     f2();
    |     ^^-- supplied 0 arguments
    |     |
    |     expected 1 argument
+   |
+note: function defined here
+  --> $DIR/E0061.rs:3:4
+   |
+LL | fn f2(a: u16) {}
+   |    ^^ ------
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0080.rs b/src/test/ui/error-codes/E0080.rs
index b31cf2e..ea3264b 100644
--- a/src/test/ui/error-codes/E0080.rs
+++ b/src/test/ui/error-codes/E0080.rs
@@ -1,6 +1,6 @@
 enum Enum {
     X = (1 << 500), //~ ERROR E0080
-    //~| attempt to shift left by 500_i32 which would overflow
+    //~| attempt to shift left by `500_i32`, which would overflow
     Y = (1 / 0) //~ ERROR E0080
 }
 
diff --git a/src/test/ui/error-codes/E0080.stderr b/src/test/ui/error-codes/E0080.stderr
index 3acd15f..60ed9a4 100644
--- a/src/test/ui/error-codes/E0080.stderr
+++ b/src/test/ui/error-codes/E0080.stderr
@@ -2,13 +2,13 @@
   --> $DIR/E0080.rs:2:9
    |
 LL |     X = (1 << 500),
-   |         ^^^^^^^^^^ attempt to shift left by 500_i32 which would overflow
+   |         ^^^^^^^^^^ attempt to shift left by `500_i32`, which would overflow
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/E0080.rs:4:9
    |
 LL |     Y = (1 / 0)
-   |         ^^^^^^^ attempt to divide 1_isize by zero
+   |         ^^^^^^^ attempt to divide `1_isize` by zero
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs
index 8ad586b..bb0c497 100644
--- a/src/test/ui/error-codes/E0388.rs
+++ b/src/test/ui/error-codes/E0388.rs
@@ -3,9 +3,9 @@
 
 const CR: &'static mut i32 = &mut C; //~ ERROR E0764
                                      //~| WARN taking a mutable
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019
-                                              //~| ERROR cannot borrow
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow
                                               //~| ERROR E0764
+
 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
                                              //~| WARN taking a mutable
 
diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr
index 39bc717..73e0b13 100644
--- a/src/test/ui/error-codes/E0388.stderr
+++ b/src/test/ui/error-codes/E0388.stderr
@@ -19,14 +19,6 @@
 LL | const CR: &'static mut i32 = &mut C;
    |                              ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/E0388.rs:6:39
-   |
-LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0388.rs:6:39
    |
@@ -59,7 +51,7 @@
 LL | static CONST_REF: &'static mut i32 = &mut C;
    |                                      ^^^^^^ `&mut` is only allowed in `const fn`
 
-error: aborting due to 5 previous errors; 2 warnings emitted
+error: aborting due to 4 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0019, E0596, E0764.
-For more information about an error, try `rustc --explain E0019`.
+Some errors have detailed explanations: E0596, E0764.
+For more information about an error, try `rustc --explain E0596`.
diff --git a/src/test/ui/error-codes/E0424.rs b/src/test/ui/error-codes/E0424.rs
index fa0c86e..6e53194 100644
--- a/src/test/ui/error-codes/E0424.rs
+++ b/src/test/ui/error-codes/E0424.rs
@@ -10,6 +10,10 @@
     fn baz(_: i32) {
         self.bar(); //~ ERROR E0424
     }
+
+    fn qux() {
+        let _ = || self.bar(); //~ ERROR E0424
+    }
 }
 
 fn main () {
diff --git a/src/test/ui/error-codes/E0424.stderr b/src/test/ui/error-codes/E0424.stderr
index 9b8a29e..20b7a4c 100644
--- a/src/test/ui/error-codes/E0424.stderr
+++ b/src/test/ui/error-codes/E0424.stderr
@@ -24,14 +24,27 @@
 LL |     fn baz(&self, _: i32) {
    |            ^^^^^^
 
+error[E0424]: expected value, found module `self`
+  --> $DIR/E0424.rs:15:20
+   |
+LL |     fn qux() {
+   |        --- this function doesn't have a `self` parameter
+LL |         let _ = || self.bar();
+   |                    ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+   |
+help: add a `self` receiver parameter to make the associated `fn` a method
+   |
+LL |     fn qux(&self) {
+   |            ^^^^^
+
 error[E0424]: expected unit struct, unit variant or constant, found module `self`
-  --> $DIR/E0424.rs:16:9
+  --> $DIR/E0424.rs:20:9
    |
 LL | fn main () {
    |    ---- this function can't have a `self` parameter
 LL |     let self = "self";
    |         ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0424`.
diff --git a/src/test/ui/error-codes/E0445.stderr b/src/test/ui/error-codes/E0445.stderr
index 953a626..1a66e0a 100644
--- a/src/test/ui/error-codes/E0445.stderr
+++ b/src/test/ui/error-codes/E0445.stderr
@@ -1,18 +1,27 @@
 error[E0445]: private trait `Foo` in public interface
   --> $DIR/E0445.rs:5:1
    |
+LL | trait Foo {
+   | --------- `Foo` declared as private
+...
 LL | pub trait Bar : Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
 
 error[E0445]: private trait `Foo` in public interface
   --> $DIR/E0445.rs:7:1
    |
+LL | trait Foo {
+   | --------- `Foo` declared as private
+...
 LL | pub struct Bar2<T: Foo>(pub T);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
 
 error[E0445]: private trait `Foo` in public interface
   --> $DIR/E0445.rs:9:1
    |
+LL | trait Foo {
+   | --------- `Foo` declared as private
+...
 LL | pub fn foo<T: Foo> (t: T) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
 
diff --git a/src/test/ui/error-codes/E0446.stderr b/src/test/ui/error-codes/E0446.stderr
index c538bae..73b6ba3 100644
--- a/src/test/ui/error-codes/E0446.stderr
+++ b/src/test/ui/error-codes/E0446.stderr
@@ -2,7 +2,7 @@
   --> $DIR/E0446.rs:4:5
    |
 LL |     struct Bar(u32);
-   |     - `Bar` declared as private
+   |     ---------------- `Bar` declared as private
 LL | 
 LL |     pub fn bar() -> Bar {
    |     ^^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/error-codes/E0520.stderr b/src/test/ui/error-codes/E0520.stderr
index 1041cce..be7b954 100644
--- a/src/test/ui/error-codes/E0520.stderr
+++ b/src/test/ui/error-codes/E0520.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default`
   --> $DIR/E0520.rs:17:5
diff --git a/src/test/ui/error-codes/E0730.stderr b/src/test/ui/error-codes/E0730.stderr
index f915f6e..356e4f3 100644
--- a/src/test/ui/error-codes/E0730.stderr
+++ b/src/test/ui/error-codes/E0730.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0730]: cannot pattern-match on an array without a fixed length
   --> $DIR/E0730.rs:6:9
diff --git a/src/test/ui/error-codes/E0771.stderr b/src/test/ui/error-codes/E0771.stderr
index 60220be..b184b59 100644
--- a/src/test/ui/error-codes/E0771.stderr
+++ b/src/test/ui/error-codes/E0771.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error[E0771]: use of non-static lifetime `'a` in const generic
   --> $DIR/E0771.rs:4:41
diff --git a/src/test/ui/error-codes/E0777.rs b/src/test/ui/error-codes/E0777.rs
new file mode 100644
index 0000000..ff70f73
--- /dev/null
+++ b/src/test/ui/error-codes/E0777.rs
@@ -0,0 +1,7 @@
+#[derive("Clone")] //~ ERROR E0777
+#[derive("Clone
+")]
+//~^^ ERROR E0777
+struct Foo;
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0777.stderr b/src/test/ui/error-codes/E0777.stderr
new file mode 100644
index 0000000..ea73c58
--- /dev/null
+++ b/src/test/ui/error-codes/E0777.stderr
@@ -0,0 +1,21 @@
+error[E0777]: expected path to a trait, found literal
+  --> $DIR/E0777.rs:1:10
+   |
+LL | #[derive("Clone")]
+   |          ^^^^^^^
+   |
+   = help: try using `#[derive(Clone)]`
+
+error[E0777]: expected path to a trait, found literal
+  --> $DIR/E0777.rs:2:10
+   |
+LL |   #[derive("Clone
+   |  __________^
+LL | | ")]
+   | |_^
+   |
+   = help: for example, write `#[derive(Debug)]` for `Debug`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0777`.
diff --git a/src/test/ui/error-codes/E0778.rs b/src/test/ui/error-codes/E0778.rs
new file mode 100644
index 0000000..60e5c25
--- /dev/null
+++ b/src/test/ui/error-codes/E0778.rs
@@ -0,0 +1,8 @@
+#![feature(isa_attribute)]
+
+#[instruction_set()] //~ ERROR
+fn no_isa_defined() {
+}
+
+fn main() {
+}
diff --git a/src/test/ui/error-codes/E0778.stderr b/src/test/ui/error-codes/E0778.stderr
new file mode 100644
index 0000000..6ecae79
--- /dev/null
+++ b/src/test/ui/error-codes/E0778.stderr
@@ -0,0 +1,9 @@
+error[E0778]: `#[instruction_set]` requires an argument
+  --> $DIR/E0778.rs:3:1
+   |
+LL | #[instruction_set()]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0778`.
diff --git a/src/test/ui/error-codes/E0779.rs b/src/test/ui/error-codes/E0779.rs
new file mode 100644
index 0000000..1b4dbce
--- /dev/null
+++ b/src/test/ui/error-codes/E0779.rs
@@ -0,0 +1,6 @@
+#![feature(isa_attribute)]
+
+#[instruction_set(arm::magic)] //~ ERROR
+fn main() {
+
+}
diff --git a/src/test/ui/error-codes/E0779.stderr b/src/test/ui/error-codes/E0779.stderr
new file mode 100644
index 0000000..da78726
--- /dev/null
+++ b/src/test/ui/error-codes/E0779.stderr
@@ -0,0 +1,9 @@
+error[E0779]: invalid instruction set specified
+  --> $DIR/E0779.rs:3:1
+   |
+LL | #[instruction_set(arm::magic)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0779`.
diff --git a/src/test/ui/error-codes/e0119/issue-28981.stderr b/src/test/ui/error-codes/e0119/issue-28981.stderr
index c22cc65..e12dd76 100644
--- a/src/test/ui/error-codes/e0119/issue-28981.stderr
+++ b/src/test/ui/error-codes/e0119/issue-28981.stderr
@@ -14,7 +14,7 @@
 LL | impl<Foo> Deref for Foo { }
    |      ^^^ type parameter `Foo` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/eval-enum.rs b/src/test/ui/eval-enum.rs
index 4ef06c7..551f10e 100644
--- a/src/test/ui/eval-enum.rs
+++ b/src/test/ui/eval-enum.rs
@@ -1,9 +1,9 @@
 enum Test {
     DivZero = 1/0,
-    //~^ attempt to divide 1_isize by zero
+    //~^ attempt to divide `1_isize` by zero
     //~| ERROR evaluation of constant value failed
     RemZero = 1%0,
-    //~^ attempt to calculate the remainder of 1_isize with a divisor of zero
+    //~^ attempt to calculate the remainder of `1_isize` with a divisor of zero
     //~| ERROR evaluation of constant value failed
 }
 
diff --git a/src/test/ui/eval-enum.stderr b/src/test/ui/eval-enum.stderr
index dd89a2d..fb4d903 100644
--- a/src/test/ui/eval-enum.stderr
+++ b/src/test/ui/eval-enum.stderr
@@ -2,13 +2,13 @@
   --> $DIR/eval-enum.rs:2:15
    |
 LL |     DivZero = 1/0,
-   |               ^^^ attempt to divide 1_isize by zero
+   |               ^^^ attempt to divide `1_isize` by zero
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/eval-enum.rs:5:15
    |
 LL |     RemZero = 1%0,
-   |               ^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
+   |               ^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/exterior.rs b/src/test/ui/exterior.rs
deleted file mode 100644
index 6f2c379..0000000
--- a/src/test/ui/exterior.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// run-pass
-
-#![allow(dead_code)]
-
-
-use std::cell::Cell;
-
-#[derive(Copy, Clone)]
-struct Point {x: isize, y: isize, z: isize}
-
-fn f(p: &Cell<Point>) {
-    assert_eq!(p.get().z, 12);
-    p.set(Point {x: 10, y: 11, z: 13});
-    assert_eq!(p.get().z, 13);
-}
-
-pub fn main() {
-    let a: Point = Point {x: 10, y: 11, z: 12};
-    let b: &Cell<Point> = &Cell::new(a);
-    assert_eq!(b.get().z, 12);
-    f(b);
-    assert_eq!(a.z, 12);
-    assert_eq!(b.get().z, 13);
-}
diff --git a/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs
new file mode 100644
index 0000000..a1efe18
--- /dev/null
+++ b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs
@@ -0,0 +1,9 @@
+#![feature(extern_types)]
+
+extern "C" {
+    pub type CrossCrate;
+}
+
+impl CrossCrate {
+    pub fn foo(&self) {}
+}
diff --git a/src/test/ui/extern/extern-types-inherent-impl.rs b/src/test/ui/extern/extern-types-inherent-impl.rs
index fc98f55..3f09ac7 100644
--- a/src/test/ui/extern/extern-types-inherent-impl.rs
+++ b/src/test/ui/extern/extern-types-inherent-impl.rs
@@ -1,19 +1,26 @@
-// run-pass
-#![allow(dead_code)]
 // Test that inherent impls can be defined for extern types.
 
+// check-pass
+// aux-build:extern-types-inherent-impl.rs
+
 #![feature(extern_types)]
 
-extern {
-    type A;
+extern crate extern_types_inherent_impl;
+use extern_types_inherent_impl::CrossCrate;
+
+extern "C" {
+    type Local;
 }
 
-impl A {
-    fn foo(&self) { }
+impl Local {
+    fn foo(&self) {}
 }
 
-fn use_foo(x: &A) {
+fn use_foo(x: &Local, y: &CrossCrate) {
+    Local::foo(x);
     x.foo();
+    CrossCrate::foo(y);
+    y.foo();
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/feature-gate-inline_const.rs b/src/test/ui/feature-gate-inline_const.rs
new file mode 100644
index 0000000..43ff90d
--- /dev/null
+++ b/src/test/ui/feature-gate-inline_const.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let _ = const {
+        //~^ ERROR inline-const is experimental [E0658]
+        true
+    };
+}
diff --git a/src/test/ui/feature-gate-inline_const.stderr b/src/test/ui/feature-gate-inline_const.stderr
new file mode 100644
index 0000000..be2f567
--- /dev/null
+++ b/src/test/ui/feature-gate-inline_const.stderr
@@ -0,0 +1,12 @@
+error[E0658]: inline-const is experimental
+  --> $DIR/feature-gate-inline_const.rs:2:13
+   |
+LL |     let _ = const {
+   |             ^^^^^
+   |
+   = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
+   = help: add `#![feature(inline_const)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gate-isa_attribute.rs b/src/test/ui/feature-gate-isa_attribute.rs
new file mode 100644
index 0000000..cb02a09
--- /dev/null
+++ b/src/test/ui/feature-gate-isa_attribute.rs
@@ -0,0 +1,6 @@
+#[instruction_set]
+//~^ ERROR the `#[instruction_set]` attribute is an experimental feature [E0658]
+//~| ERROR malformed `instruction_set` attribute input
+//~| ERROR must specify an instruction set [E0778]
+fn main() {
+}
diff --git a/src/test/ui/feature-gate-isa_attribute.stderr b/src/test/ui/feature-gate-isa_attribute.stderr
new file mode 100644
index 0000000..2a95a80
--- /dev/null
+++ b/src/test/ui/feature-gate-isa_attribute.stderr
@@ -0,0 +1,25 @@
+error: malformed `instruction_set` attribute input
+  --> $DIR/feature-gate-isa_attribute.rs:1:1
+   |
+LL | #[instruction_set]
+   | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]`
+
+error[E0658]: the `#[instruction_set]` attribute is an experimental feature
+  --> $DIR/feature-gate-isa_attribute.rs:1:1
+   |
+LL | #[instruction_set]
+   | ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #74727 <https://github.com/rust-lang/rust/issues/74727> for more information
+   = help: add `#![feature(isa_attribute)]` to the crate attributes to enable
+
+error[E0778]: must specify an instruction set
+  --> $DIR/feature-gate-isa_attribute.rs:1:1
+   |
+LL | #[instruction_set]
+   | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0658, E0778.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs
index 3ac8ba5..6404b2c 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs
@@ -1,3 +1,6 @@
+//~ NOTE: not an `extern crate` item
+//~^ NOTE: not a function or static
+//~^^ NOTE: not a function or closure
 // This is testing whether various builtin attributes signals an
 // error or warning when put in "weird" places.
 //
@@ -7,9 +10,25 @@
 
 // ignore-tidy-linelength
 
-// Crate-level is accepted, though it is almost certainly unused?
+#![macro_export]
+//~^ ERROR: `macro_export` attribute cannot be used at crate level
+#![main]
+//~^ ERROR: `main` attribute cannot be used at crate level
+#![start]
+//~^ ERROR: `start` attribute cannot be used at crate level
+#![repr()]
+//~^ ERROR: `repr` attribute cannot be used at crate level
+#![path = "3800"]
+//~^ ERROR: `path` attribute cannot be used at crate level
+#![automatically_derived]
+//~^ ERROR: `automatically_derived` attribute cannot be used at crate level
+#![no_mangle]
+#![no_link]
+//~^ ERROR: attribute should be applied to an `extern crate` item
+#![export_name = "2200"]
+//~^ ERROR: attribute should be applied to a function or static
 #![inline]
-
+//~^ ERROR: attribute should be applied to function or closure
 #[inline]
 //~^ ERROR attribute should be applied to function or closure
 mod inline {
@@ -88,4 +107,40 @@
     //~| NOTE not a function or static
 }
 
+#[main]
+//~^ ERROR: `main` attribute can only be used on functions
+mod main {
+    mod inner { #![main] }
+    //~^ ERROR: `main` attribute can only be used on functions
+
+    // for `fn f()` case, see feature-gate-main.rs
+
+    #[main] struct S;
+    //~^ ERROR: `main` attribute can only be used on functions
+
+    #[main] type T = S;
+    //~^ ERROR: `main` attribute can only be used on functions
+
+    #[main] impl S { }
+    //~^ ERROR: `main` attribute can only be used on functions
+}
+
+#[start]
+//~^ ERROR: `start` attribute can only be used on functions
+mod start {
+    mod inner { #![start] }
+    //~^ ERROR: `start` attribute can only be used on functions
+
+    // for `fn f()` case, see feature-gate-start.rs
+
+    #[start] struct S;
+    //~^ ERROR: `start` attribute can only be used on functions
+
+    #[start] type T = S;
+    //~^ ERROR: `start` attribute can only be used on functions
+
+    #[start] impl S { }
+    //~^ ERROR: `start` attribute can only be used on functions
+}
+
 fn main() {}
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr
index c9255d2..3ca1bd2e 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -1,5 +1,5 @@
 error: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:41:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
@@ -8,8 +8,68 @@
    = 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: `main` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:1
+   |
+LL | #[main]
+   | ^^^^^^^
+
+error: `main` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:17
+   |
+LL |     mod inner { #![main] }
+   |                 ^^^^^^^^
+
+error: `main` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:118:5
+   |
+LL |     #[main] struct S;
+   |     ^^^^^^^
+
+error: `main` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:121:5
+   |
+LL |     #[main] type T = S;
+   |     ^^^^^^^
+
+error: `main` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:124:5
+   |
+LL |     #[main] impl S { }
+   |     ^^^^^^^
+
+error: `start` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:128:1
+   |
+LL | #[start]
+   | ^^^^^^^^
+
+error: `start` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:17
+   |
+LL |     mod inner { #![start] }
+   |                 ^^^^^^^^^
+
+error: `start` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:136:5
+   |
+LL |     #[start] struct S;
+   |     ^^^^^^^^
+
+error: `start` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:5
+   |
+LL |     #[start] type T = S;
+   |     ^^^^^^^^
+
+error: `start` attribute can only be used on functions
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:142:5
+   |
+LL |     #[start] impl S { }
+   |     ^^^^^^^^
+
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:13:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
    |
 LL |   #[inline]
    |   ^^^^^^^^^
@@ -24,7 +84,7 @@
    | |_- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:41:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:1
    |
 LL |   #[no_link]
    |   ^^^^^^^^^^
@@ -39,7 +99,7 @@
    | |_- not an `extern crate` item
 
 error: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:1
    |
 LL |   #[export_name = "2200"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,84 +113,138 @@
 LL | | }
    | |_- not a function or static
 
+error: attribute should be applied to an `extern crate` item
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
+   |
+LL | #![no_link]
+   | ^^^^^^^^^^^
+
+error: attribute should be applied to a function or static
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
+   |
+LL | #![export_name = "2200"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
+   |
+LL | #![inline]
+   | ^^^^^^^^^^
+
+error: `macro_export` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:13:1
+   |
+LL | #![macro_export]
+   | ^^^^^^^^^^^^^^^^
+
+error: `main` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:15:1
+   |
+LL | #![main]
+   | ^^^^^^^^
+
+error: `start` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
+   |
+LL | #![start]
+   | ^^^^^^^^^
+
+error: `repr` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
+   |
+LL | #![repr()]
+   | ^^^^^^^^^^
+
+error: `path` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
+   |
+LL | #![path = "3800"]
+   | ^^^^^^^^^^^^^^^^^
+
+error: `automatically_derived` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1
+   |
+LL | #![automatically_derived]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:37:17
    |
 LL |     mod inner { #![inline] }
    |     ------------^^^^^^^^^^-- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5
    |
 LL |     #[inline] struct S;
    |     ^^^^^^^^^ --------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:51:5
    |
 LL |     #[inline] type T = S;
    |     ^^^^^^^^^ ----------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:55:5
    |
 LL |     #[inline] impl S { }
    |     ^^^^^^^^^ ---------- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:17
    |
 LL |     mod inner { #![no_link] }
    |     ------------^^^^^^^^^^^-- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:69:5
    |
 LL |     #[no_link] fn f() { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:73:5
    |
 LL |     #[no_link] struct S;
    |     ^^^^^^^^^^ --------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:77:5
    |
 LL |     #[no_link]type T = S;
    |     ^^^^^^^^^^----------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:62:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:81:5
    |
 LL |     #[no_link] impl S { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:17
    |
 LL |     mod inner { #![export_name="2200"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^-- not a function or static
 
 error: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:97:5
    |
 LL |     #[export_name = "2200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static
 
 error: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:101:5
    |
 LL |     #[export_name = "2200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static
 
 error: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:105:5
    |
 LL |     #[export_name = "2200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static
 
-error: aborting due to 17 previous errors
+error: aborting due to 36 previous errors
 
 For more information about this error, try `rustc --explain E0518`.
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
index f94434f..aba6c08 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
@@ -1,3 +1,6 @@
+//~ NOTE not a function
+//~^ NOTE not a foreign function or static
+//~^^ NOTE not a function or static
 // This test enumerates as many compiler-builtin ungated attributes as
 // possible (that is, all the mutually compatible ones), and checks
 // that we get "expected" (*) warnings for each in the various weird
@@ -52,20 +55,8 @@
 #![forbid(x5200)] //~ WARN unknown lint: `x5200`
 #![deny(x5100)] //~ WARN unknown lint: `x5100`
 #![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs)
-#![macro_export] //~ WARN unused attribute
 // skipping testing of cfg
 // skipping testing of cfg_attr
-#![main] //~ WARN unused attribute
-#![start] //~ WARN unused attribute
-// see issue-43106-gating-of-test.rs for crate-level; but non crate-level is below at "4200"
-// see issue-43106-gating-of-bench.rs for crate-level; but non crate-level is below at "4100"
-#![repr()]
-//~^ WARN unused attribute
-#![path = "3800"] //~ WARN unused attribute
-#![automatically_derived] //~ WARN unused attribute
-#![no_mangle]
-#![no_link] //~ WARN unused attribute
-// see issue-43106-gating-of-derive.rs
 #![should_panic] //~ WARN unused attribute
 #![ignore] //~ WARN unused attribute
 #![no_implicit_prelude]
@@ -75,12 +66,16 @@
 // (cannot easily test gating of crate-level #[no_std]; but non crate-level is below at "2600")
 #![proc_macro_derive()] //~ WARN unused attribute
 #![doc = "2400"]
-#![cold]
-#![export_name = "2200"]
+#![cold] //~ WARN attribute should be applied to a function
+//~^ WARN
 // see issue-43106-gating-of-builtin-attrs-error.rs
 #![link()]
 #![link_name = "1900"]
+//~^ WARN attribute should be applied to a foreign function
+//~^^ WARN this was previously accepted by the compiler
 #![link_section = "1800"]
+//~^ WARN attribute should be applied to a function or static
+//~^^ WARN this was previously accepted by the compiler
 // see issue-43106-gating-of-rustc_deprecated.rs
 #![must_use]
 // see issue-43106-gating-of-stable.rs
@@ -254,42 +249,6 @@
     //~| HELP may be removed in a future compiler version
 }
 
-#[main]
-//~^ WARN unused attribute
-mod main {
-    mod inner { #![main] }
-    //~^ WARN unused attribute
-
-    // for `fn f()` case, see feature-gate-main.rs
-
-    #[main] struct S;
-    //~^ WARN unused attribute
-
-    #[main] type T = S;
-    //~^ WARN unused attribute
-
-    #[main] impl S { }
-    //~^ WARN unused attribute
-}
-
-#[start]
-//~^ WARN unused attribute
-mod start {
-    mod inner { #![start] }
-    //~^ WARN unused attribute
-
-    // for `fn f()` case, see feature-gate-start.rs
-
-    #[start] struct S;
-    //~^ WARN unused attribute
-
-    #[start] type T = S;
-    //~^ WARN unused attribute
-
-    #[start] impl S { }
-    //~^ WARN unused attribute
-}
-
 // At time of unit test authorship, if compiling without `--test` then
 // non-crate-level #[test] attributes seem to be ignored.
 
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
index 461c1bd..ef9c9ef 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
@@ -1,185 +1,185 @@
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:9
    |
 LL | #![warn(x5400)]
    |         ^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:28
    |
 LL | #![warn(unused_attributes, unknown_lints)]
    |                            ^^^^^^^^^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:51:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:10
    |
 LL | #![allow(x5300)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:11
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:11
    |
 LL | #![forbid(x5200)]
    |           ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:9
    |
 LL | #![deny(x5100)]
    |         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:8
    |
 LL | #[warn(x5400)]
    |        ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:25
    |
 LL |     mod inner { #![warn(x5400)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12
    |
 LL |     #[warn(x5400)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12
    |
 LL |     #[warn(x5400)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:12
    |
 LL |     #[warn(x5400)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:12
    |
 LL |     #[warn(x5400)] impl S { }
    |            ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:9
    |
 LL | #[allow(x5300)]
    |         ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:26
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:26
    |
 LL |     mod inner { #![allow(x5300)] }
    |                          ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13
    |
 LL |     #[allow(x5300)] fn f() { }
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13
    |
 LL |     #[allow(x5300)] struct S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:13
    |
 LL |     #[allow(x5300)] type T = S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:13
    |
 LL |     #[allow(x5300)] impl S { }
    |             ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:10
    |
 LL | #[forbid(x5200)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:27
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:27
    |
 LL |     mod inner { #![forbid(x5200)] }
    |                           ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14
    |
 LL |     #[forbid(x5200)] fn f() { }
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14
    |
 LL |     #[forbid(x5200)] struct S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:14
    |
 LL |     #[forbid(x5200)] type T = S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:14
    |
 LL |     #[forbid(x5200)] impl S { }
    |              ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:8
    |
 LL | #[deny(x5100)]
    |        ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:25
    |
 LL |     mod inner { #![deny(x5100)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12
    |
 LL |     #[deny(x5100)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12
    |
 LL |     #[deny(x5100)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:12
    |
 LL |     #[deny(x5100)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:12
    |
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:438:1
    |
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:441:17
    |
 LL |     mod inner { #![macro_escape] }
    |                 ^^^^^^^^^^^^^^^^
@@ -187,7 +187,7 @@
    = help: try an outer attribute: `#[macro_use]`
 
 warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:17
    |
 LL |     mod inner { #![plugin_registrar] }
    |                 ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
@@ -195,49 +195,49 @@
    = note: `#[warn(deprecated)]` on by default
 
 warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:236:5
    |
 LL |     #[plugin_registrar] struct S;
    |     ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
 warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5
    |
 LL |     #[plugin_registrar] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
 warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5
    |
 LL |     #[plugin_registrar] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
 warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:223:1
    |
 LL | #[plugin_registrar]
    | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
 warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:1
    |
 LL | #![plugin_registrar]
    | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
 warning: use of deprecated attribute `crate_id`: no longer used.
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:91:1
    |
 LL | #![crate_id = "10"]
    | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
 
 warning: use of deprecated attribute `no_start`: no longer used.
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:1
    |
 LL | #![no_start]
    | ^^^^^^^^^^^^ help: remove this attribute
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:1
    |
 LL |   #[no_mangle]
    |   ^^^^^^^^^^^^
@@ -252,14 +252,14 @@
    | |_- not a function or static
    |
 note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:9
    |
 LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:1
    |
 LL |   #[cold]
    |   ^^^^^^^
@@ -276,7 +276,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:529:1
    |
 LL |   #[link_name = "1900"]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -293,7 +293,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:568:1
    |
 LL |   #[link_section = "1800"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -309,8 +309,32 @@
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to a function
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
+   |
+LL | #![cold]
+   | ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to a foreign function or static
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:73:1
+   |
+LL | #![link_name = "1900"]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:76:1
+   |
+LL | #![link_section = "1800"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to a function or static
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:17
    |
 LL |     mod inner { #![no_mangle] }
    |     ------------^^^^^^^^^^^^^-- not a function or static
@@ -318,7 +342,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:5
    |
 LL |     #[no_mangle] struct S;
    |     ^^^^^^^^^^^^ --------- not a function or static
@@ -326,7 +350,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5
    |
 LL |     #[no_mangle] type T = S;
    |     ^^^^^^^^^^^^ ----------- not a function or static
@@ -334,7 +358,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5
    |
 LL |     #[no_mangle] impl S { }
    |     ^^^^^^^^^^^^ ---------- not a function or static
@@ -342,7 +366,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:506:17
    |
 LL |     mod inner { #![cold] }
    |     ------------^^^^^^^^-- not a function
@@ -350,7 +374,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:554:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:5
    |
 LL |     #[cold] struct S;
    |     ^^^^^^^ --------- not a function
@@ -358,7 +382,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:5
    |
 LL |     #[cold] type T = S;
    |     ^^^^^^^ ----------- not a function
@@ -366,7 +390,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:564:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:523:5
    |
 LL |     #[cold] impl S { }
    |     ^^^^^^^ ---------- not a function
@@ -374,7 +398,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:535:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -384,13 +408,13 @@
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 help: try `#[link(name = "1900")]` instead
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:535:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:17
    |
 LL |     mod inner { #![link_name="1900"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static
@@ -398,7 +422,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5
    |
 LL |     #[link_name = "1900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -406,7 +430,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:593:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:552:5
    |
 LL |     #[link_name = "1900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static
@@ -414,7 +438,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:557:5
    |
 LL |     #[link_name = "1900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static
@@ -422,7 +446,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:562:5
    |
 LL |     #[link_name = "1900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -430,7 +454,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:574:17
    |
 LL |     mod inner { #![link_section="1800"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static
@@ -438,7 +462,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5
    |
 LL |     #[link_section = "1800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static
@@ -446,7 +470,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:586:5
    |
 LL |     #[link_section = "1800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static
@@ -454,7 +478,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:591:5
    |
 LL |     #[link_section = "1800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static
@@ -462,7 +486,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:101:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:12
    |
 LL | #![feature(rust1)]
    |            ^^^^^
@@ -470,952 +494,850 @@
    = note: `#[warn(stable_features)]` on by default
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5
    |
 LL |     #[macro_use] fn f() { }
    |     ^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:5
    |
 LL |     #[macro_use] struct S;
    |     ^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:5
    |
 LL |     #[macro_use] type T = S;
    |     ^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:200:5
    |
 LL |     #[macro_use] impl S { }
    |     ^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:17
    |
 LL |     mod inner { #![macro_export] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5
    |
 LL |     #[macro_export] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:218:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5
    |
 LL |     #[macro_export] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:5
    |
 LL |     #[macro_export] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:5
    |
 LL |     #[macro_export] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:1
    |
 LL | #[macro_export]
    | ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:17
    |
 LL |     mod inner { #![plugin_registrar] }
    |                 ^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:236:5
    |
 LL |     #[plugin_registrar] struct S;
    |     ^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5
    |
 LL |     #[plugin_registrar] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5
    |
 LL |     #[plugin_registrar] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:223:1
    |
 LL | #[plugin_registrar]
    | ^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17
-   |
-LL |     mod inner { #![main] }
-   |                 ^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:5
-   |
-LL |     #[main] struct S;
-   |     ^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5
-   |
-LL |     #[main] type T = S;
-   |     ^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5
-   |
-LL |     #[main] impl S { }
-   |     ^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1
-   |
-LL | #[main]
-   | ^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:17
-   |
-LL |     mod inner { #![start] }
-   |                 ^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:5
-   |
-LL |     #[start] struct S;
-   |     ^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:5
-   |
-LL |     #[start] type T = S;
-   |     ^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5
-   |
-LL |     #[start] impl S { }
-   |     ^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:1
-   |
-LL | #[start]
-   | ^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:301:5
    |
 LL |     #[path = "3800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:304:5
    |
 LL |     #[path = "3800"]  struct S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:307:5
    |
 LL |     #[path = "3800"] type T = S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:5
    |
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:317:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:320:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:5
    |
 LL |     #[automatically_derived] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5
    |
 LL |     #[automatically_derived] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:17
    |
 LL |     mod inner { #![should_panic] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
    |
 LL |     #[should_panic] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
    |
 LL |     #[should_panic] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5
    |
 LL |     #[should_panic] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5
    |
 LL |     #[should_panic] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:17
    |
 LL |     mod inner { #![ignore] }
    |                 ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5
    |
 LL |     #[ignore] fn f() { }
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5
    |
 LL |     #[ignore] struct S;
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5
    |
 LL |     #[ignore] type T = S;
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5
    |
 LL |     #[ignore] impl S { }
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:17
    |
 LL |     mod inner { #![no_implicit_prelude] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:5
    |
 LL |     #[no_implicit_prelude] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5
    |
 LL |     #[no_implicit_prelude] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5
    |
 LL |     #[no_implicit_prelude] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5
    |
 LL |     #[no_implicit_prelude] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:1
    |
 LL | #[no_implicit_prelude]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:17
    |
 LL |     mod inner { #![reexport_test_harness_main="2900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:5
    |
 LL |     #[reexport_test_harness_main = "2900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5
    |
 LL |     #[reexport_test_harness_main = "2900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5
    |
 LL |     #[reexport_test_harness_main = "2900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5
    |
 LL |     #[reexport_test_harness_main = "2900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:1
    |
 LL | #[reexport_test_harness_main = "2900"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:5
    |
 LL |     #[macro_escape] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5
    |
 LL |     #[macro_escape] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:5
    |
 LL |     #[macro_escape] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:454:5
    |
 LL |     #[macro_escape] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:1
    |
 LL | #![plugin_registrar]
    | ^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1
-   |
-LL | #![macro_export]
-   | ^^^^^^^^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1
-   |
-LL | #![main]
-   | ^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1
-   |
-LL | #![start]
-   | ^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
-   |
-LL | #![repr()]
-   | ^^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
-   |
-LL | #![path = "3800"]
-   | ^^^^^^^^^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1
-   |
-LL | #![automatically_derived]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1
-   |
-LL | #![no_link]
-   | ^^^^^^^^^^^
-
-warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
    |
 LL | #![should_panic]
    | ^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1
    |
 LL | #![ignore]
    | ^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:76:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1
    |
 LL | #![proc_macro_derive()]
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: 219 warnings emitted
+warning: 205 warnings emitted
 
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
index 9bce274..38be85f 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
@@ -14,6 +14,7 @@
 trait _Tr3 {
     type A: Iterator<Item: Copy>;
     //~^ ERROR associated type bounds are unstable
+    //~| ERROR the trait bound `<<Self as _Tr3>::A as Iterator>::Item: Copy` is not satisfied
 
     type B: Iterator<Item: 'static>;
     //~^ ERROR associated type bounds are unstable
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
index 7f2704e..be5d351 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr
@@ -8,7 +8,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:18:22
+  --> $DIR/feature-gate-associated_type_bounds.rs:19:22
    |
 LL |     type B: Iterator<Item: 'static>;
    |                      ^^^^^^^^^^^^^
@@ -17,7 +17,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:22:20
+  --> $DIR/feature-gate-associated_type_bounds.rs:23:20
    |
 LL | struct _St1<T: Tr1<As1: Tr2>> {
    |                    ^^^^^^^^
@@ -26,7 +26,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:29:18
+  --> $DIR/feature-gate-associated_type_bounds.rs:30:18
    |
 LL | enum _En1<T: Tr1<As1: Tr2>> {
    |                  ^^^^^^^^
@@ -35,7 +35,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:36:19
+  --> $DIR/feature-gate-associated_type_bounds.rs:37:19
    |
 LL | union _Un1<T: Tr1<As1: Tr2>> {
    |                   ^^^^^^^^
@@ -44,7 +44,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:43:37
+  --> $DIR/feature-gate-associated_type_bounds.rs:44:37
    |
 LL | type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
    |                                     ^^^^^^^^^^
@@ -53,7 +53,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:46:22
+  --> $DIR/feature-gate-associated_type_bounds.rs:47:22
    |
 LL | fn _apit(_: impl Tr1<As1: Copy>) {}
    |                      ^^^^^^^^^
@@ -62,7 +62,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:48:26
+  --> $DIR/feature-gate-associated_type_bounds.rs:49:26
    |
 LL | fn _apit_dyn(_: &dyn Tr1<As1: Copy>) {}
    |                          ^^^^^^^^^
@@ -71,7 +71,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:51:24
+  --> $DIR/feature-gate-associated_type_bounds.rs:52:24
    |
 LL | fn _rpit() -> impl Tr1<As1: Copy> { S1 }
    |                        ^^^^^^^^^
@@ -80,7 +80,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:54:31
+  --> $DIR/feature-gate-associated_type_bounds.rs:55:31
    |
 LL | fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) }
    |                               ^^^^^^^^^
@@ -89,7 +89,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:57:23
+  --> $DIR/feature-gate-associated_type_bounds.rs:58:23
    |
 LL | const _cdef: impl Tr1<As1: Copy> = S1;
    |                       ^^^^^^^^^
@@ -98,7 +98,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:63:24
+  --> $DIR/feature-gate-associated_type_bounds.rs:64:24
    |
 LL | static _sdef: impl Tr1<As1: Copy> = S1;
    |                        ^^^^^^^^^
@@ -107,7 +107,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0658]: associated type bounds are unstable
-  --> $DIR/feature-gate-associated_type_bounds.rs:70:21
+  --> $DIR/feature-gate-associated_type_bounds.rs:71:21
    |
 LL |     let _: impl Tr1<As1: Copy> = S1;
    |                     ^^^^^^^^^
@@ -116,7 +116,7 @@
    = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:57:14
+  --> $DIR/feature-gate-associated_type_bounds.rs:58:14
    |
 LL | const _cdef: impl Tr1<As1: Copy> = S1;
    |              ^^^^^^^^^^^^^^^^^^^
@@ -124,7 +124,7 @@
    = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:63:15
+  --> $DIR/feature-gate-associated_type_bounds.rs:64:15
    |
 LL | static _sdef: impl Tr1<As1: Copy> = S1;
    |               ^^^^^^^^^^^^^^^^^^^
@@ -132,14 +132,30 @@
    = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-associated_type_bounds.rs:70:12
+  --> $DIR/feature-gate-associated_type_bounds.rs:71:12
    |
 LL |     let _: impl Tr1<As1: Copy> = S1;
    |            ^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
 
-error: aborting due to 16 previous errors
+error[E0277]: the trait bound `<<Self as _Tr3>::A as Iterator>::Item: Copy` is not satisfied
+  --> $DIR/feature-gate-associated_type_bounds.rs:15:28
+   |
+LL |     type A: Iterator<Item: Copy>;
+   |                            ^^^^ the trait `Copy` is not implemented for `<<Self as _Tr3>::A as Iterator>::Item`
+   | 
+  ::: $SRC_DIR/core/src/marker.rs:LL:COL
+   |
+LL | pub trait Copy: Clone {
+   | --------------------- required by this bound in `Copy`
+   |
+help: consider further restricting the associated type
+   |
+LL | trait _Tr3 where <<Self as _Tr3>::A as Iterator>::Item: Copy {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Some errors have detailed explanations: E0562, E0658.
-For more information about an error, try `rustc --explain E0562`.
+error: aborting due to 17 previous errors
+
+Some errors have detailed explanations: E0277, E0562, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
index 17548d7..1d2be36 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs
@@ -15,6 +15,7 @@
     //~^ ERROR generic associated types are unstable
     type Pointer2<U32> = Box<U32>;
     //~^ ERROR generic associated types are unstable
+    //~| ERROR the trait bound `U32: Clone` is not satisfied
 }
 
 trait Bar {
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
index 8499b1a..266008c 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
@@ -44,7 +44,7 @@
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:21:5
+  --> $DIR/feature-gate-generic_associated_types.rs:22:5
    |
 LL |     type Assoc where Self: Sized;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,7 +53,7 @@
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
 error[E0658]: where clauses on associated types are unstable
-  --> $DIR/feature-gate-generic_associated_types.rs:26:5
+  --> $DIR/feature-gate-generic_associated_types.rs:27:5
    |
 LL |     type Assoc where Self: Sized = Foo;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,6 +61,18 @@
    = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
    = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
 
-error: aborting due to 7 previous errors
+error[E0277]: the trait bound `U32: Clone` is not satisfied
+  --> $DIR/feature-gate-generic_associated_types.rs:16:5
+   |
+LL |     type Pointer2<U32> = Box<U32>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `U32`
+   |
+help: consider restricting type parameter `U32`
+   |
+LL |     type Pointer2<U32: Clone> = Box<U32>;
+   |                      ^^^^^^^
 
-For more information about this error, try `rustc --explain E0658`.
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0277, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr b/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr
index aa84c27..d1f4ed5 100644
--- a/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr
+++ b/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr
@@ -2,7 +2,10 @@
   --> $DIR/feature-gate-negate-unsigned.rs:10:23
    |
 LL |     let _max: usize = -1;
-   |                       ^^ cannot apply unary operator `-`
+   |                       ^^
+   |                       |
+   |                       cannot apply unary operator `-`
+   |                       help: you may have meant the maximum value of `usize`: `usize::MAX`
    |
    = note: unsigned values cannot be negated
 
diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
index e3272e8..b61d560 100644
--- a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
+++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
@@ -1,26 +1,35 @@
 error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
   --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:38
    |
+LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
+   |                                      ^^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23
+   |
 LL | trait NonObjectSafe1: Sized {}
-   |       --------------  ----- ...because it requires `Self: Sized`
+   |       --------------  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
-   |                                      ^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object
 
 error[E0038]: the trait `NonObjectSafe2` cannot be made into an object
   --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:36
    |
+LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe2` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:7:8
+   |
 LL | trait NonObjectSafe2 {
    |       -------------- this trait cannot be made into an object...
 LL |     fn static_fn() {}
-   |        --------- ...because associated function `static_fn` has no `self` parameter
-...
-LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe2` cannot be made into an object
+   |        ^^^^^^^^^ ...because associated function `static_fn` has no `self` parameter
+help: consider turning `static_fn` into a method by giving it a `&self` argument
    |
-help: consider turning `static_fn` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn static_fn(&self) {}
+   |                  ^^^^^
+help: alternatively, consider constraining `static_fn` so it does not apply to trait objects
    |
 LL |     fn static_fn() where Self: Sized {}
    |                    ^^^^^^^^^^^^^^^^^
@@ -28,39 +37,46 @@
 error[E0038]: the trait `NonObjectSafe3` cannot be made into an object
   --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:35
    |
+LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object
+   |
+   = help: consider moving `foo` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:11:8
+   |
 LL | trait NonObjectSafe3 {
    |       -------------- this trait cannot be made into an object...
 LL |     fn foo<T>(&self);
-   |        --- ...because method `foo` has generic type parameters
-...
-LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe3` cannot be made into an object
-   |
-   = help: consider moving `foo` to another trait
+   |        ^^^ ...because method `foo` has generic type parameters
 
 error[E0038]: the trait `NonObjectSafe4` cannot be made into an object
   --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:35
    |
+LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object
+   |
+   = help: consider moving `foo` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:15:19
+   |
 LL | trait NonObjectSafe4 {
    |       -------------- this trait cannot be made into an object...
 LL |     fn foo(&self, &Self);
-   |                   ----- ...because method `foo` references the `Self` type in this parameter
-...
-LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe4` cannot be made into an object
-   |
-   = help: consider moving `foo` to another trait
+   |                   ^^^^^ ...because method `foo` references the `Self` type in this parameter
 
 error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
   --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:16
    |
+LL | impl Trait for dyn NonObjectSafe1 {}
+   |                ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23
+   |
 LL | trait NonObjectSafe1: Sized {}
-   |       --------------  ----- ...because it requires `Self: Sized`
+   |       --------------  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL | impl Trait for dyn NonObjectSafe1 {}
-   |                ^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs
index 3b6c979..ffe297a 100644
--- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs
+++ b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.rs
@@ -1,3 +1,4 @@
+// ignore-compare-mode-chalk
 use std::fmt::Debug;
 
 type Foo = impl Debug; //~ ERROR `impl Trait` in type aliases is unstable
diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
index 8bab0d0..b32cf94 100644
--- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
+++ b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:3:12
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:4:12
    |
 LL | type Foo = impl Debug;
    |            ^^^^^^^^^^
@@ -8,7 +8,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:11:16
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:12:16
    |
 LL |     type Baa = impl Debug;
    |                ^^^^^^^^^^
@@ -17,7 +17,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: associated type defaults are unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:22:5
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:23:5
    |
 LL |     type Assoc = impl Debug;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@
    = help: add `#![feature(associated_type_defaults)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:22:18
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:23:18
    |
 LL |     type Assoc = impl Debug;
    |                  ^^^^^^^^^^
@@ -35,7 +35,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:28:24
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:29:24
    |
 LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>);
    |                        ^^^^^^^^^^
@@ -44,7 +44,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:28:37
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:29:37
    |
 LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>);
    |                                     ^^^^^^^^^^
@@ -53,7 +53,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:28:49
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:29:49
    |
 LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>);
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:28:70
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:29:70
    |
 LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>);
    |                                                                      ^^^^^^^^^^
@@ -71,7 +71,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:39:21
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:40:21
    |
 LL |     type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug);
    |                     ^^^^^^^^^^
@@ -80,7 +80,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:39:34
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:40:34
    |
 LL |     type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug);
    |                                  ^^^^^^^^^^
@@ -89,7 +89,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:39:46
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:40:46
    |
 LL |     type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug);
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -98,7 +98,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:39:67
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:40:67
    |
 LL |     type Baa = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug> + Debug);
    |                                                                   ^^^^^^^^^^
@@ -107,7 +107,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:22:18
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:23:18
    |
 LL |     type Assoc = impl Debug;
    |                  ^^^^^^^^^^
diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
index 9ee0e6f..f5f9631c 100644
--- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
+++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-linelength
+
 union U1 { // OK
     a: u8,
 }
@@ -6,15 +8,23 @@
     a: T,
 }
 
-union U3 { //~ ERROR unions with non-`Copy` fields are unstable
+union U22<T> { // OK
+    a: std::mem::ManuallyDrop<T>,
+}
+
+union U3 {
     a: String, //~ ERROR unions may not contain fields that need dropping
 }
 
-union U4<T> { //~ ERROR unions with non-`Copy` fields are unstable
+union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test!
+    a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
+}
+
+union U4<T> {
     a: T, //~ ERROR unions may not contain fields that need dropping
 }
 
-union U5 { //~ ERROR unions with `Drop` implementations are unstable
+union U5 { // Having a drop impl is OK
     a: u8,
 }
 
diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
index 3a123ea..ed97387 100644
--- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
+++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
@@ -1,61 +1,37 @@
-error[E0658]: unions with non-`Copy` fields are unstable
-  --> $DIR/feature-gate-untagged_unions.rs:9:1
+error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
+  --> $DIR/feature-gate-untagged_unions.rs:20:5
    |
-LL | / union U3 {
-LL | |     a: String,
-LL | | }
-   | |_^
-   |
-   = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
-   = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
-
-error[E0658]: unions with non-`Copy` fields are unstable
-  --> $DIR/feature-gate-untagged_unions.rs:13:1
-   |
-LL | / union U4<T> {
-LL | |     a: T,
-LL | | }
-   | |_^
-   |
-   = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
-   = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
-
-error[E0658]: unions with `Drop` implementations are unstable
-  --> $DIR/feature-gate-untagged_unions.rs:17:1
-   |
-LL | / union U5 {
-LL | |     a: u8,
-LL | | }
-   | |_^
+LL |     a: std::cell::RefCell<i32>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
    = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
 
 error[E0740]: unions may not contain fields that need dropping
-  --> $DIR/feature-gate-untagged_unions.rs:10:5
+  --> $DIR/feature-gate-untagged_unions.rs:16:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
    |
 note: `std::mem::ManuallyDrop` can be used to wrap the type
-  --> $DIR/feature-gate-untagged_unions.rs:10:5
+  --> $DIR/feature-gate-untagged_unions.rs:16:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
 
 error[E0740]: unions may not contain fields that need dropping
-  --> $DIR/feature-gate-untagged_unions.rs:14:5
+  --> $DIR/feature-gate-untagged_unions.rs:24:5
    |
 LL |     a: T,
    |     ^^^^
    |
 note: `std::mem::ManuallyDrop` can be used to wrap the type
-  --> $DIR/feature-gate-untagged_unions.rs:14:5
+  --> $DIR/feature-gate-untagged_unions.rs:24:5
    |
 LL |     a: T,
    |     ^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0658, E0740.
 For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fmt/format-string-error-2.stderr b/src/test/ui/fmt/format-string-error-2.stderr
index d202044..c421fe4 100644
--- a/src/test/ui/fmt/format-string-error-2.stderr
+++ b/src/test/ui/fmt/format-string-error-2.stderr
@@ -2,9 +2,7 @@
   --> $DIR/format-string-error-2.rs:77:20
    |
 LL |     println!("\x7B}\u8 {", 1);
-   |                    ^^-
-   |                      |
-   |                      help: format of unicode escape sequences uses braces: `\u{8}`
+   |                    ^^^ help: format of unicode escape sequences uses braces: `\u{8}`
 
 error: invalid format string: expected `'}'`, found `'a'`
   --> $DIR/format-string-error-2.rs:5:5
diff --git a/src/test/ui/for/for-c-in-str.rs b/src/test/ui/for/for-c-in-str.rs
index df66127..97a4ea5 100644
--- a/src/test/ui/for/for-c-in-str.rs
+++ b/src/test/ui/for/for-c-in-str.rs
@@ -1,14 +1,16 @@
-// E0277 should point exclusively at line 14, not the entire for loop span
+// E0277 should point exclusively at line 6, not the entire for loop span
 
 fn main() {
     for c in "asdf" {
-    //~^ ERROR `&str` is not an iterator
-    //~| NOTE `&str` is not an iterator
-    //~| HELP the trait `Iterator` is not implemented for `&str`
-    //~| NOTE required by `into_iter`
-    //~| NOTE in this expansion of desugaring of `for` loop
-    //~| NOTE in this expansion of desugaring of `for` loop
-    //~| NOTE in this expansion of desugaring of `for` loop
+        //~^ ERROR `&str` is not an iterator
+        //~| NOTE `&str` is not an iterator
+        //~| HELP the trait `Iterator` is not implemented for `&str`
+        //~| NOTE required because of the requirements on the impl of `IntoIterator` for `&str`
+        //~| NOTE required by `into_iter`
+        //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE in this expansion of desugaring of `for` loop
+        //~| NOTE in this expansion of desugaring of `for` loop
         println!();
     }
 }
diff --git a/src/test/ui/for/for-c-in-str.stderr b/src/test/ui/for/for-c-in-str.stderr
index b0f959b..18e46e1 100644
--- a/src/test/ui/for/for-c-in-str.stderr
+++ b/src/test/ui/for/for-c-in-str.stderr
@@ -5,6 +5,7 @@
    |              ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
    |
    = help: the trait `Iterator` is not implemented for `&str`
+   = note: required because of the requirements on the impl of `IntoIterator` for `&str`
    = note: required by `into_iter`
 
 error: aborting due to previous error
diff --git a/src/test/ui/for/for-loop-bogosity.stderr b/src/test/ui/for/for-loop-bogosity.stderr
index ccacd65..0d94096 100644
--- a/src/test/ui/for/for-loop-bogosity.stderr
+++ b/src/test/ui/for/for-loop-bogosity.stderr
@@ -5,6 +5,7 @@
    |              ^^^^^ `MyStruct` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `MyStruct`
+   = note: required because of the requirements on the impl of `IntoIterator` for `MyStruct`
    = note: required by `into_iter`
 
 error: aborting due to previous error
diff --git a/src/test/ui/format-ref-cell.rs b/src/test/ui/format-ref-cell.rs
deleted file mode 100644
index afb2f84..0000000
--- a/src/test/ui/format-ref-cell.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// run-pass
-
-use std::cell::RefCell;
-
-pub fn main() {
-    let name = RefCell::new("rust");
-    let what = RefCell::new("rocks");
-    let msg = format!("{name} {}", &*what.borrow(), name=&*name.borrow());
-    assert_eq!(msg, "rust rocks".to_string());
-}
diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
index 16a5ab2..5043a3b 100644
--- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
+++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]`
   --> $DIR/generator-yielding-or-returning-itself.rs:15:5
    |
 LL | pub fn want_cyclic_generator_return<T>(_: T)
@@ -14,7 +14,7 @@
            see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
            for more information
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]`
   --> $DIR/generator-yielding-or-returning-itself.rs:28:5
    |
 LL | pub fn want_cyclic_generator_yield<T>(_: T)
diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr
index 84d2a85..96a8d6d 100644
--- a/src/test/ui/generator/issue-68112.stderr
+++ b/src/test/ui/generator/issue-68112.stderr
@@ -29,7 +29,7 @@
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
-   = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 t:Arc<RefCell<i32>> {()}]`
+   = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 {()}]`
    = note: required because it appears within the type `impl Generator`
    = note: required because it appears within the type `impl Generator`
    = note: required because it appears within the type `{impl Generator, ()}`
diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr
index 32527c4..2384ed3 100644
--- a/src/test/ui/generator/not-send-sync.stderr
+++ b/src/test/ui/generator/not-send-sync.stderr
@@ -9,7 +9,7 @@
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: required because of the requirements on the impl of `Send` for `&Cell<i32>`
-   = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&Cell<i32> _]`
+   = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 _]`
 
 error: generator cannot be shared between threads safely
   --> $DIR/not-send-sync.rs:9:5
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.rs b/src/test/ui/generator/print/generator-print-verbose-1.rs
new file mode 100644
index 0000000..fe06877
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-1.rs
@@ -0,0 +1,60 @@
+// compile-flags: -Zverbose
+
+// Same as: src/test/ui/generator/issue-68112.stderr
+
+#![feature(generators, generator_trait)]
+
+use std::{
+    cell::RefCell,
+    sync::Arc,
+    pin::Pin,
+    ops::{Generator, GeneratorState},
+};
+
+pub struct Ready<T>(Option<T>);
+impl<T> Generator<()> for Ready<T> {
+    type Return = T;
+    type Yield = ();
+    fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> {
+        GeneratorState::Complete(self.0.take().unwrap())
+    }
+}
+pub fn make_gen1<T>(t: T) -> Ready<T> {
+    Ready(Some(t))
+}
+
+fn require_send(_: impl Send) {}
+
+fn make_non_send_generator() -> impl Generator<Return = Arc<RefCell<i32>>> {
+    make_gen1(Arc::new(RefCell::new(0)))
+}
+
+fn test1() {
+    let send_gen = || {
+        let _non_send_gen = make_non_send_generator();
+        yield;
+    };
+    require_send(send_gen);
+    //~^ ERROR generator cannot be sent between threads
+}
+
+pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+    || {
+        yield;
+        t
+    }
+}
+fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
+    make_gen2(Arc::new(RefCell::new(0)))
+}
+
+fn test2() {
+    let send_gen = || {
+        let _non_send_gen = make_non_send_generator2();
+        yield;
+    };
+    require_send(send_gen);
+    //~^ ERROR `RefCell<i32>` cannot be shared between threads safely
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr
new file mode 100644
index 0000000..b5c6358
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr
@@ -0,0 +1,40 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/generator-print-verbose-1.rs:37:5
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ---- required by this bound in `require_send`
+...
+LL |     require_send(send_gen);
+   |     ^^^^^^^^^^^^ generator is not `Send`
+   |
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
+note: generator is not `Send` as this value is used across a yield
+  --> $DIR/generator-print-verbose-1.rs:35:9
+   |
+LL |         let _non_send_gen = make_non_send_generator();
+   |             ------------- has type `Opaque(DefId(0:24 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+LL |     };
+   |     - `_non_send_gen` is later dropped here
+
+error[E0277]: `RefCell<i32>` cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-1.rs:56:5
+   |
+LL | fn require_send(_: impl Send) {}
+   |                         ---- required by this bound in `require_send`
+...
+LL |     require_send(send_gen);
+   |     ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
+   = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
+   = note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]`
+   = note: required because it appears within the type `Opaque(DefId(0:29 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+   = note: required because it appears within the type `Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])`
+   = note: required because it appears within the type `{Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}`
+   = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/print/generator-print-verbose-2.rs b/src/test/ui/generator/print/generator-print-verbose-2.rs
new file mode 100644
index 0000000..d914719
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-2.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Zverbose
+
+// Same as test/ui/generator/not-send-sync.rs
+#![feature(generators)]
+
+use std::cell::Cell;
+
+fn main() {
+    fn assert_sync<T: Sync>(_: T) {}
+    fn assert_send<T: Send>(_: T) {}
+
+    assert_sync(|| {
+        //~^ ERROR: generator cannot be shared between threads safely
+        let a = Cell::new(2);
+        yield;
+    });
+
+    let a = Cell::new(2);
+    assert_send(|| {
+        //~^ ERROR: E0277
+        drop(&a);
+        yield;
+    });
+}
diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr
new file mode 100644
index 0000000..f239490
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr
@@ -0,0 +1,36 @@
+error[E0277]: `Cell<i32>` cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-2.rs:19:5
+   |
+LL |     fn assert_send<T: Send>(_: T) {}
+   |                       ---- required by this bound in `assert_send`
+...
+LL |     assert_send(|| {
+   |     ^^^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `Cell<i32>`
+   = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell<i32>`
+   = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#17t]`
+
+error: generator cannot be shared between threads safely
+  --> $DIR/generator-print-verbose-2.rs:12:5
+   |
+LL |     fn assert_sync<T: Sync>(_: T) {}
+   |                       ---- required by this bound in `assert_sync`
+...
+LL |     assert_sync(|| {
+   |     ^^^^^^^^^^^ generator is not `Sync`
+   |
+   = help: within `[main::{closure#0} upvar_tys=() {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>`
+note: generator is not `Sync` as this value is used across a yield
+  --> $DIR/generator-print-verbose-2.rs:15:9
+   |
+LL |         let a = Cell::new(2);
+   |             - has type `Cell<i32>` which is not `Sync`
+LL |         yield;
+   |         ^^^^^ yield occurs here, with `a` maybe used later
+LL |     });
+   |     - `a` is later dropped here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/print/generator-print-verbose-3.rs b/src/test/ui/generator/print/generator-print-verbose-3.rs
new file mode 100644
index 0000000..8689539
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-3.rs
@@ -0,0 +1,12 @@
+// compile-flags: -Zverbose
+
+#![feature(generators, generator_trait)]
+
+fn main() {
+    let x = "Type mismatch test";
+    let generator :() = || {
+    //~^ ERROR mismatched types
+        yield 1i32;
+        return x
+    };
+}
diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr
new file mode 100644
index 0000000..d156462
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/generator-print-verbose-3.rs:7:25
+   |
+LL |       let generator :() = || {
+   |  ____________________--___^
+   | |                    |
+   | |                    expected due to this
+LL | |
+LL | |         yield 1i32;
+LL | |         return x
+LL | |     };
+   | |_____^ expected `()`, found generator
+   |
+   = note: expected unit type `()`
+              found generator `[main::{closure#0} upvar_tys=(unavailable)]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr
index 2bcf66d..8e3c2f67 100644
--- a/src/test/ui/generator/sized-yield.stderr
+++ b/src/test/ui/generator/sized-yield.stderr
@@ -16,6 +16,11 @@
    |
 LL |    Pin::new(&mut gen).resume(());
    |                       ^^^^^^ doesn't have a size known at compile-time
+   | 
+  ::: $SRC_DIR/core/src/ops/generator.rs:LL:COL
+   |
+LL | pub enum GeneratorState<Y, R> {
+   |                         - required by this bound in `GeneratorState`
    |
    = help: the trait `Sized` is not implemented for `str`
 
diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr
index 216b707..881064d 100644
--- a/src/test/ui/generator/static-not-unpin.stderr
+++ b/src/test/ui/generator/static-not-unpin.stderr
@@ -1,11 +1,11 @@
-error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned
+error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` cannot be unpinned
   --> $DIR/static-not-unpin.rs:14:18
    |
 LL | fn assert_unpin<T: Unpin>(_: T) {
    |                    ----- required by this bound in `assert_unpin`
 ...
 LL |     assert_unpin(generator);
-   |                  ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]`
+   |                  ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
index 260fbb2..4abc054 100644
--- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -6,8 +6,13 @@
    |
    = note: expected type `std::result::Result<{integer}, _>`
               found type `{integer}`
+note: return type inferred to be `std::result::Result<{integer}, _>` here
+  --> $DIR/type-mismatch-signature-deduction.rs:8:20
+   |
+LL |             return Ok(6);
+   |                    ^^^^^
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as Generator>::Return == i32`
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
    |
 LL | fn foo() -> impl Generator<Return = i32> {
@@ -15,7 +20,6 @@
    |
    = note: expected enum `std::result::Result<{integer}, _>`
               found type `i32`
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs
new file mode 100644
index 0000000..d8aa354
--- /dev/null
+++ b/src/test/ui/generator/yielding-in-match-guards.rs
@@ -0,0 +1,24 @@
+// check-pass
+// edition:2018
+
+// This test is derived from
+// https://github.com/rust-lang/rust/issues/72651#issuecomment-668720468
+
+// This test demonstrates that, in `async fn g()`,
+// indeed a temporary borrow `y` from `x` is live
+// while `f().await` is being evaluated.
+// Thus, `&'_ u8` should be included in type signature
+// of the underlying generator.
+
+async fn f() -> u8 { 1 }
+
+pub async fn g(x: u8) {
+    match x {
+        y if f().await == y => (),
+        _ => (),
+    }
+}
+
+fn main() {
+    let _ = g(10);
+}
diff --git a/src/test/ui/generic-associated-types/auxiliary/foo_defn.rs b/src/test/ui/generic-associated-types/auxiliary/foo_defn.rs
new file mode 100644
index 0000000..0e8e148
--- /dev/null
+++ b/src/test/ui/generic-associated-types/auxiliary/foo_defn.rs
@@ -0,0 +1,8 @@
+#![feature(generic_associated_types)]
+
+use std::{future::Future, pin::Pin};
+
+pub trait Foo {
+    type Bar: AsRef<()>;
+    fn foo(&self) -> Pin<Box<dyn Future<Output = Self::Bar> + '_>>;
+}
diff --git a/src/test/ui/generic-associated-types/cross-crate-bounds.rs b/src/test/ui/generic-associated-types/cross-crate-bounds.rs
new file mode 100644
index 0000000..8934a07
--- /dev/null
+++ b/src/test/ui/generic-associated-types/cross-crate-bounds.rs
@@ -0,0 +1,32 @@
+// regression test for #73816
+// We handled bounds differently when `feature(generic_associated_types)` was enabled
+
+// edition:2018
+// aux-build:foo_defn.rs
+
+extern crate foo_defn;
+
+use foo_defn::Foo;
+use std::{future::Future, pin::Pin};
+
+pub struct FooImpl;
+
+impl Foo for FooImpl {
+    type Bar = ();
+    //~^ ERROR the trait bound `(): AsRef<()>` is not satisfied
+    fn foo(&self) -> Pin<Box<dyn Future<Output = Self::Bar> + '_>> {
+        panic!()
+    }
+}
+
+async fn foo() {
+    bar(&FooImpl).await;
+}
+
+async fn bar<F: Foo>(foo: &F) {
+    foo.foo().await.as_ref();
+}
+
+fn main() {
+    // futures::executor::block_on(foo());
+}
diff --git a/src/test/ui/generic-associated-types/cross-crate-bounds.stderr b/src/test/ui/generic-associated-types/cross-crate-bounds.stderr
new file mode 100644
index 0000000..d96c5f4
--- /dev/null
+++ b/src/test/ui/generic-associated-types/cross-crate-bounds.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `(): AsRef<()>` is not satisfied
+  --> $DIR/cross-crate-bounds.rs:15:5
+   |
+LL |     type Bar = ();
+   |     ^^^^^^^^^^^^^^ the trait `AsRef<()>` is not implemented for `()`
+   | 
+  ::: $DIR/auxiliary/foo_defn.rs:6:15
+   |
+LL |     type Bar: AsRef<()>;
+   |               --------- required by this bound in `foo_defn::Foo::Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.rs b/src/test/ui/generic-associated-types/generic-associated-types-where.rs
index 1a94796..27970b1 100644
--- a/src/test/ui/generic-associated-types/generic-associated-types-where.rs
+++ b/src/test/ui/generic-associated-types/generic-associated-types-where.rs
@@ -19,8 +19,9 @@
 impl Foo for Bar {
     type Assoc = usize;
     type Assoc2<T> = Vec<T>;
+    //~^ ERROR `T` doesn't implement `std::fmt::Display`
     type Assoc3<T> where T: Iterator = Vec<T>;
-    //~^ impl has stricter requirements than trait
+    //~^ ERROR impl has stricter requirements than trait
     type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator<Item=T>;
     type NoGenerics = ::std::cell::Cell<i32>;
 }
diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
index c95765d..da8b625 100644
--- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
+++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
@@ -1,5 +1,17 @@
+error[E0277]: `T` doesn't implement `std::fmt::Display`
+  --> $DIR/generic-associated-types-where.rs:21:5
+   |
+LL |     type Assoc2<T> = Vec<T>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
+   |
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+help: consider restricting type parameter `T`
+   |
+LL |     type Assoc2<T: std::fmt::Display> = Vec<T>;
+   |                  ^^^^^^^^^^^^^^^^^^^
+
 error[E0276]: impl has stricter requirements than trait
-  --> $DIR/generic-associated-types-where.rs:22:5
+  --> $DIR/generic-associated-types-where.rs:23:5
    |
 LL |     type Assoc3<T>;
    |     --------------- definition of `Assoc3` from trait
@@ -7,6 +19,7 @@
 LL |     type Assoc3<T> where T: Iterator = Vec<T>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0276`.
+Some errors have detailed explanations: E0276, E0277.
+For more information about an error, try `rustc --explain E0276`.
diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs
index 77bebc98..089a214 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.rs
+++ b/src/test/ui/generic-associated-types/impl_bounds.rs
@@ -16,6 +16,7 @@
     //~^ ERROR the parameter type `T` may not live long enough
     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
     //~^ ERROR lifetime bound not satisfied
+    //~| ERROR lifetime bound not satisfied
     type C where Self: Copy = String;
     //~^ ERROR the trait bound `T: Copy` is not satisfied
 }
diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr
index 0546e38..645d292 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.stderr
+++ b/src/test/ui/generic-associated-types/impl_bounds.stderr
@@ -24,8 +24,25 @@
 LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
    |            ^^
 
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/impl_bounds.rs:17:5
+   |
+LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the associated item at 17:12
+  --> $DIR/impl_bounds.rs:17:12
+   |
+LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+   |            ^^
+note: but lifetime parameter must outlive the lifetime `'b` as defined on the associated item at 17:16
+  --> $DIR/impl_bounds.rs:17:16
+   |
+LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+   |                ^^
+
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/impl_bounds.rs:19:5
+  --> $DIR/impl_bounds.rs:20:5
    |
 LL |     type C where Self: Copy = String;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
@@ -37,7 +54,7 @@
 LL | impl<T: Copy> Foo for Fooy<T> {
    |       ^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0277, E0310, E0478.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/impl_bounds_ok.rs b/src/test/ui/generic-associated-types/impl_bounds_ok.rs
index 2387b89..98aa82a 100644
--- a/src/test/ui/generic-associated-types/impl_bounds_ok.rs
+++ b/src/test/ui/generic-associated-types/impl_bounds_ok.rs
@@ -10,11 +10,12 @@
     type C where Self: Clone;
 }
 
+#[derive(Clone)]
 struct Fooy;
 
 impl Foo for Fooy {
     type A<'a> = (&'a ());
-    type B<'a, 'b> = (&'a(), &'b ());
+    type B<'a: 'b, 'b> = (&'a(), &'b ());
     type C = String;
 }
 
@@ -24,7 +25,7 @@
 impl<T> Foo for Fooer<T> {
     type A<'x> where T: 'x = (&'x ());
     type B<'u, 'v> where 'u: 'v = (&'v &'u ());
-    type C where Self: ToOwned = String;
+    type C where Self: Clone + ToOwned = String;
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
index 6ba79dd..b380f0d 100644
--- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
+++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
@@ -11,7 +11,7 @@
   --> $DIR/issue-68641-check-gat-bounds.rs:15:5
    |
 LL |     type Item<'a>: Copy;
-   |     -------------------- required by `UnsafeCopy::Item`
+   |                    ---- required by this bound in `UnsafeCopy::Item`
 ...
 LL |     type Item<'a> = T;
    |     ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
index 15a66e2..6195047 100644
--- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
+++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
@@ -11,7 +11,7 @@
   --> $DIR/issue-68642-broken-llvm-ir.rs:15:5
    |
 LL |     type F<'a>: Fn() -> u32;
-   |     ------------------------ required by `Fun::F`
+   |                 ----------- required by this bound in `Fun::F`
 ...
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
index 9b2ddb2..1398061 100644
--- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
+++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
@@ -11,7 +11,7 @@
   --> $DIR/issue-68643-broken-mir.rs:15:5
    |
 LL |     type F<'a>: Fn() -> u32;
-   |     ------------------------ required by `Fun::F`
+   |                 ----------- required by this bound in `Fun::F`
 ...
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
index f7bfab3..8112425 100644
--- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
+++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
@@ -11,7 +11,7 @@
   --> $DIR/issue-68644-codegen-selection.rs:15:5
    |
 LL |     type F<'a>: Fn() -> u32;
-   |     ------------------------ required by `Fun::F`
+   |                 ----------- required by this bound in `Fun::F`
 ...
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
index 6c2d330..22f50b3 100644
--- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
+++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
@@ -11,7 +11,7 @@
   --> $DIR/issue-68645-codegen-fulfillment.rs:15:5
    |
 LL |     type F<'a>: Fn() -> u32;
-   |     ------------------------ required by `Fun::F`
+   |                 ----------- required by this bound in `Fun::F`
 ...
 LL |     type F<'a> = Self;
    |     ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
index a933615..c4ee2c4 100644
--- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
+++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
@@ -11,7 +11,7 @@
   --> $DIR/issue-68656-unsized-values.rs:16:5
    |
 LL |     type Item<'a>: std::ops::Deref<Target = T>;
-   |     ------------------------------------------- required by `UnsafeCopy::Item`
+   |                                    ---------- required by this bound in `UnsafeCopy::Item`
 ...
 LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
    |      - this type parameter
diff --git a/src/test/ui/generic-associated-types/issue-74816.rs b/src/test/ui/generic-associated-types/issue-74816.rs
new file mode 100644
index 0000000..7543972
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74816.rs
@@ -0,0 +1,23 @@
+#![feature(associated_type_defaults)]
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Trait1 {
+    fn foo();
+}
+
+trait Trait2 {
+    type Associated: Trait1 = Self;
+    //~^ ERROR: the trait bound `Self: Trait1` is not satisfied
+    //~| the size for values of type `Self` cannot be known
+}
+
+impl Trait2 for () {}
+
+fn call_foo<T: Trait2>() {
+    T::Associated::foo()
+}
+
+fn main() {
+    call_foo::<()>()
+}
diff --git a/src/test/ui/generic-associated-types/issue-74816.stderr b/src/test/ui/generic-associated-types/issue-74816.stderr
new file mode 100644
index 0000000..64bc94d
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-74816.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the trait bound `Self: Trait1` is not satisfied
+  --> $DIR/issue-74816.rs:10:5
+   |
+LL |     type Associated: Trait1 = Self;
+   |     ^^^^^^^^^^^^^^^^^------^^^^^^^^
+   |     |                |
+   |     |                required by this bound in `Trait2::Associated`
+   |     the trait `Trait1` is not implemented for `Self`
+   |
+help: consider further restricting `Self`
+   |
+LL | trait Trait2: Trait1 {
+   |             ^^^^^^^^
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/issue-74816.rs:10:5
+   |
+LL |     type Associated: Trait1 = Self;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     doesn't have a size known at compile-time
+   |     required by this bound in `Trait2::Associated`
+   |
+help: consider further restricting `Self`
+   |
+LL | trait Trait2: Sized {
+   |             ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs
new file mode 100644
index 0000000..0cd676a
--- /dev/null
+++ b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs
@@ -0,0 +1,62 @@
+// Like `projection-bound-cycle.rs` but this avoids using
+// `feature(trivial_bounds)`.
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+
+trait Print {
+    fn print();
+}
+
+trait Foo {
+    type Item: Sized where <Self as Foo>::Item: Sized;
+}
+
+struct Number<T> { t: T }
+
+impl<T> Foo for Number<T> {
+    // Well-formedness checks require that the following
+    // goal is true:
+    // ```
+    // if ([T]: Sized) { # if the where clauses hold
+    //     [T]: Sized # then the bound on the associated type hold
+    // }
+    // ```
+    // which it is :)
+    type Item where [T]: Sized = [T];
+}
+
+struct OnlySized<T> where T: Sized { f: T }
+impl<T> Print for OnlySized<T> {
+    fn print() {
+        println!("{}", std::mem::size_of::<T>());
+    }
+}
+
+trait Bar {
+    type Assoc: Print;
+}
+
+impl<T> Bar for T where T: Foo {
+    // This is not ok, we need to prove `wf(<T as Foo>::Item)`, which requires
+    // knowing that `<T as Foo>::Item: Sized` to satisfy the where clause. We
+    // can use the bound on `Foo::Item` for this, but that requires
+    // `wf(<T as Foo>::Item)`, which is an invalid cycle.
+    type Assoc = OnlySized<<T as Foo>::Item>;
+    //~^ ERROR overflow evaluating the requirement `<T as Foo>::Item: Sized`
+}
+
+fn foo<T: Print>() {
+    T::print() // oops, in fact `T = OnlySized<str>` which is ill-formed
+}
+
+fn bar<T: Bar>() {
+    // we have `FromEnv(T: Bar)` hence
+    // `<T as Bar>::Assoc` is well-formed and
+    // `Implemented(<T as Bar>::Assoc: Print)` hold
+    foo::<<T as Bar>::Assoc>()
+}
+
+fn main() {
+    bar::<Number<u8>>()
+}
diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr
new file mode 100644
index 0000000..d27e46f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr
@@ -0,0 +1,21 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/projection-bound-cycle-generic.rs:4:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
+  --> $DIR/projection-bound-cycle-generic.rs:45:5
+   |
+LL | struct OnlySized<T> where T: Sized { f: T }
+   |                  - required by this bound in `OnlySized`
+...
+LL |     type Assoc = OnlySized<<T as Foo>::Item>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle.rs b/src/test/ui/generic-associated-types/projection-bound-cycle.rs
new file mode 100644
index 0000000..5043fe5
--- /dev/null
+++ b/src/test/ui/generic-associated-types/projection-bound-cycle.rs
@@ -0,0 +1,64 @@
+// Test case from Chalk.
+// Make sure that we make sure that we don't allow arbitrary bounds to be
+// proven when a bound and a where clause of an associated type are the same.
+
+#![feature(generic_associated_types)]
+//~^ WARNING the feature `generic_associated_types` is incomplete
+#![feature(trivial_bounds)]
+
+trait Print {
+    fn print();
+}
+
+trait Foo {
+    type Item: Sized where <Self as Foo>::Item: Sized;
+}
+
+struct Number { }
+
+impl Foo for Number {
+    // Well-formedness checks require that the following
+    // goal is true:
+    // ```
+    // if (str: Sized) { # if the where clauses hold
+    //     str: Sized # then the bound on the associated type hold
+    // }
+    // ```
+    // which it is :)
+    type Item where str: Sized = str;
+}
+
+struct OnlySized<T> where T: Sized { f: T }
+impl<T> Print for OnlySized<T> {
+    fn print() {
+        println!("{}", std::mem::size_of::<T>());
+    }
+}
+
+trait Bar {
+    type Assoc: Print;
+}
+
+impl<T> Bar for T where T: Foo {
+    // This is not ok, we need to prove `wf(<T as Foo>::Item)`, which requires
+    // knowing that `<T as Foo>::Item: Sized` to satisfy the where clause. We
+    // can use the bound on `Foo::Item` for this, but that requires
+    // `wf(<T as Foo>::Item)`, which is an invalid cycle.
+    type Assoc = OnlySized<<T as Foo>::Item>;
+    //~^ ERROR overflow evaluating the requirement `<T as Foo>::Item: Sized`
+}
+
+fn foo<T: Print>() {
+    T::print() // oops, in fact `T = OnlySized<str>` which is ill-formed
+}
+
+fn bar<T: Bar>() {
+    // we have `FromEnv(T: Bar)` hence
+    // `<T as Bar>::Assoc` is well-formed and
+    // `Implemented(<T as Bar>::Assoc: Print)` hold
+    foo::<<T as Bar>::Assoc>()
+}
+
+fn main() {
+    bar::<Number>()
+}
diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle.stderr b/src/test/ui/generic-associated-types/projection-bound-cycle.stderr
new file mode 100644
index 0000000..400b664
--- /dev/null
+++ b/src/test/ui/generic-associated-types/projection-bound-cycle.stderr
@@ -0,0 +1,21 @@
+warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/projection-bound-cycle.rs:5:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
+
+error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
+  --> $DIR/projection-bound-cycle.rs:47:5
+   |
+LL | struct OnlySized<T> where T: Sized { f: T }
+   |                  - required by this bound in `OnlySized`
+...
+LL |     type Assoc = OnlySized<<T as Foo>::Item>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs
index 7510c58..99d5bcf 100644
--- a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs
+++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs
@@ -7,7 +7,7 @@
 
 impl<'b> ATy for &'b () {
     type Item<'a> = &'b ();
-    //~^ ERROR does not fulfill the required lifetime
+    //~^ ERROR  the type `&'b ()` does not fulfill the required lifetime
 }
 
 trait StaticTy {
@@ -16,7 +16,7 @@
 
 impl StaticTy for () {
     type Item<'a> = &'a ();
-    //~^ ERROR does not fulfill the required lifetime
+    //~^ ERROR  the type `&'a ()` does not fulfill the required lifetime
 }
 
 fn main() {}
diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.rs b/src/test/ui/generics/generic-arg-mismatch-recover.rs
similarity index 100%
rename from src/test/ui/generic/generic-arg-mismatch-recover.rs
rename to src/test/ui/generics/generic-arg-mismatch-recover.rs
diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.stderr b/src/test/ui/generics/generic-arg-mismatch-recover.stderr
similarity index 100%
rename from src/test/ui/generic/generic-arg-mismatch-recover.stderr
rename to src/test/ui/generics/generic-arg-mismatch-recover.stderr
diff --git a/src/test/ui/generic/generic-extern-lifetime.rs b/src/test/ui/generics/generic-extern-lifetime.rs
similarity index 100%
rename from src/test/ui/generic/generic-extern-lifetime.rs
rename to src/test/ui/generics/generic-extern-lifetime.rs
diff --git a/src/test/ui/generic/generic-extern-lifetime.stderr b/src/test/ui/generics/generic-extern-lifetime.stderr
similarity index 100%
rename from src/test/ui/generic/generic-extern-lifetime.stderr
rename to src/test/ui/generics/generic-extern-lifetime.stderr
diff --git a/src/test/ui/generic/generic-extern.rs b/src/test/ui/generics/generic-extern.rs
similarity index 100%
rename from src/test/ui/generic/generic-extern.rs
rename to src/test/ui/generics/generic-extern.rs
diff --git a/src/test/ui/generic/generic-extern.stderr b/src/test/ui/generics/generic-extern.stderr
similarity index 100%
rename from src/test/ui/generic/generic-extern.stderr
rename to src/test/ui/generics/generic-extern.stderr
diff --git a/src/test/ui/generic/generic-impl-less-params-with-defaults.rs b/src/test/ui/generics/generic-impl-less-params-with-defaults.rs
similarity index 100%
rename from src/test/ui/generic/generic-impl-less-params-with-defaults.rs
rename to src/test/ui/generics/generic-impl-less-params-with-defaults.rs
diff --git a/src/test/ui/generic/generic-impl-less-params-with-defaults.stderr b/src/test/ui/generics/generic-impl-less-params-with-defaults.stderr
similarity index 100%
rename from src/test/ui/generic/generic-impl-less-params-with-defaults.stderr
rename to src/test/ui/generics/generic-impl-less-params-with-defaults.stderr
diff --git a/src/test/ui/generic/generic-impl-more-params-with-defaults.rs b/src/test/ui/generics/generic-impl-more-params-with-defaults.rs
similarity index 100%
rename from src/test/ui/generic/generic-impl-more-params-with-defaults.rs
rename to src/test/ui/generics/generic-impl-more-params-with-defaults.rs
diff --git a/src/test/ui/generic/generic-impl-more-params-with-defaults.stderr b/src/test/ui/generics/generic-impl-more-params-with-defaults.stderr
similarity index 100%
rename from src/test/ui/generic/generic-impl-more-params-with-defaults.stderr
rename to src/test/ui/generics/generic-impl-more-params-with-defaults.stderr
diff --git a/src/test/ui/generic/generic-lifetime-trait-impl.rs b/src/test/ui/generics/generic-lifetime-trait-impl.rs
similarity index 100%
rename from src/test/ui/generic/generic-lifetime-trait-impl.rs
rename to src/test/ui/generics/generic-lifetime-trait-impl.rs
diff --git a/src/test/ui/generic/generic-lifetime-trait-impl.stderr b/src/test/ui/generics/generic-lifetime-trait-impl.stderr
similarity index 100%
rename from src/test/ui/generic/generic-lifetime-trait-impl.stderr
rename to src/test/ui/generics/generic-lifetime-trait-impl.stderr
diff --git a/src/test/ui/generic/generic-no-mangle.fixed b/src/test/ui/generics/generic-no-mangle.fixed
similarity index 100%
rename from src/test/ui/generic/generic-no-mangle.fixed
rename to src/test/ui/generics/generic-no-mangle.fixed
diff --git a/src/test/ui/generic/generic-no-mangle.rs b/src/test/ui/generics/generic-no-mangle.rs
similarity index 100%
rename from src/test/ui/generic/generic-no-mangle.rs
rename to src/test/ui/generics/generic-no-mangle.rs
diff --git a/src/test/ui/generic/generic-no-mangle.stderr b/src/test/ui/generics/generic-no-mangle.stderr
similarity index 100%
rename from src/test/ui/generic/generic-no-mangle.stderr
rename to src/test/ui/generics/generic-no-mangle.stderr
diff --git a/src/test/ui/generic/generic-non-trailing-defaults.rs b/src/test/ui/generics/generic-non-trailing-defaults.rs
similarity index 100%
rename from src/test/ui/generic/generic-non-trailing-defaults.rs
rename to src/test/ui/generics/generic-non-trailing-defaults.rs
diff --git a/src/test/ui/generic/generic-non-trailing-defaults.stderr b/src/test/ui/generics/generic-non-trailing-defaults.stderr
similarity index 100%
rename from src/test/ui/generic/generic-non-trailing-defaults.stderr
rename to src/test/ui/generics/generic-non-trailing-defaults.stderr
diff --git a/src/test/ui/generic/generic-param-attrs.rs b/src/test/ui/generics/generic-param-attrs.rs
similarity index 100%
rename from src/test/ui/generic/generic-param-attrs.rs
rename to src/test/ui/generics/generic-param-attrs.rs
diff --git a/src/test/ui/generic/generic-type-less-params-with-defaults.rs b/src/test/ui/generics/generic-type-less-params-with-defaults.rs
similarity index 100%
rename from src/test/ui/generic/generic-type-less-params-with-defaults.rs
rename to src/test/ui/generics/generic-type-less-params-with-defaults.rs
diff --git a/src/test/ui/generic/generic-type-less-params-with-defaults.stderr b/src/test/ui/generics/generic-type-less-params-with-defaults.stderr
similarity index 100%
rename from src/test/ui/generic/generic-type-less-params-with-defaults.stderr
rename to src/test/ui/generics/generic-type-less-params-with-defaults.stderr
diff --git a/src/test/ui/generic/generic-type-more-params-with-defaults.rs b/src/test/ui/generics/generic-type-more-params-with-defaults.rs
similarity index 100%
rename from src/test/ui/generic/generic-type-more-params-with-defaults.rs
rename to src/test/ui/generics/generic-type-more-params-with-defaults.rs
diff --git a/src/test/ui/generic/generic-type-more-params-with-defaults.stderr b/src/test/ui/generics/generic-type-more-params-with-defaults.stderr
similarity index 100%
rename from src/test/ui/generic/generic-type-more-params-with-defaults.stderr
rename to src/test/ui/generics/generic-type-more-params-with-defaults.stderr
diff --git a/src/test/ui/generic/generic-type-params-forward-mention.rs b/src/test/ui/generics/generic-type-params-forward-mention.rs
similarity index 100%
rename from src/test/ui/generic/generic-type-params-forward-mention.rs
rename to src/test/ui/generics/generic-type-params-forward-mention.rs
diff --git a/src/test/ui/generic/generic-type-params-forward-mention.stderr b/src/test/ui/generics/generic-type-params-forward-mention.stderr
similarity index 100%
rename from src/test/ui/generic/generic-type-params-forward-mention.stderr
rename to src/test/ui/generics/generic-type-params-forward-mention.stderr
diff --git a/src/test/ui/generic/generic-type-params-name-repr.rs b/src/test/ui/generics/generic-type-params-name-repr.rs
similarity index 100%
rename from src/test/ui/generic/generic-type-params-name-repr.rs
rename to src/test/ui/generics/generic-type-params-name-repr.rs
diff --git a/src/test/ui/generic/generic-type-params-name-repr.stderr b/src/test/ui/generics/generic-type-params-name-repr.stderr
similarity index 100%
rename from src/test/ui/generic/generic-type-params-name-repr.stderr
rename to src/test/ui/generics/generic-type-params-name-repr.stderr
diff --git a/src/test/ui/generic/param-in-ct-in-ty-param-default.rs b/src/test/ui/generics/param-in-ct-in-ty-param-default.rs
similarity index 100%
rename from src/test/ui/generic/param-in-ct-in-ty-param-default.rs
rename to src/test/ui/generics/param-in-ct-in-ty-param-default.rs
diff --git a/src/test/ui/generic/param-in-ct-in-ty-param-default.stderr b/src/test/ui/generics/param-in-ct-in-ty-param-default.stderr
similarity index 100%
rename from src/test/ui/generic/param-in-ct-in-ty-param-default.stderr
rename to src/test/ui/generics/param-in-ct-in-ty-param-default.stderr
diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/glob-resolve1.stderr
index 3c818f3..cd128c1 100644
--- a/src/test/ui/glob-resolve1.stderr
+++ b/src/test/ui/glob-resolve1.stderr
@@ -24,7 +24,17 @@
   --> $DIR/glob-resolve1.rs:24:5
    |
 LL |     B;
-   |     ^ help: try using the enum's variant: `B::B1`
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/glob-resolve1.rs:12:5
+   |
+LL |     pub enum B { B1 }
+   |     ^^^^^^^^^^^^^^^^^
+help: you might have meant to use the following enum variant
+   |
+LL |     B::B1;
+   |     ^^^^^
 
 error[E0425]: cannot find value `C` in this scope
   --> $DIR/glob-resolve1.rs:25:5
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs
index 7cddf5f..b087322 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs
@@ -2,7 +2,7 @@
 #![feature(exclusive_range_pattern)]
 
 fn main() {
-    let "a".. = "a"; //~ ERROR only char and numeric types are allowed in range patterns
-    let .."a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns
-    let ..="a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns
+    let "a".. = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns
+    let .."a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns
+    let ..="a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns
 }
diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr
index 68ca363..df0dae5 100644
--- a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr
+++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr
@@ -1,16 +1,16 @@
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/half-open-range-pats-bad-types.rs:5:9
    |
 LL |     let "a".. = "a";
    |         ^^^ this is of type `&'static str` but it should be `char` or numeric
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/half-open-range-pats-bad-types.rs:6:11
    |
 LL |     let .."a" = "a";
    |           ^^^ this is of type `&'static str` but it should be `char` or numeric
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/half-open-range-pats-bad-types.rs:7:12
    |
 LL |     let ..="a" = "a";
diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr
index bd08fc1..2cc1c7a 100644
--- a/src/test/ui/hrtb/issue-58451.stderr
+++ b/src/test/ui/hrtb/issue-58451.stderr
@@ -1,16 +1,16 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/issue-58451.rs:12:9
    |
-LL | / fn f<I>(i: I)
-LL | | where
-LL | |     I: IntoIterator,
-LL | |     I::Item: for<'a> Into<&'a ()>,
-   | |__________________________________- defined here
-...
-LL |       f(&[f()]);
-   |           ^-- supplied 0 arguments
-   |           |
-   |           expected 1 argument
+LL |     f(&[f()]);
+   |         ^-- supplied 0 arguments
+   |         |
+   |         expected 1 argument
+   |
+note: function defined here
+  --> $DIR/issue-58451.rs:5:4
+   |
+LL | fn f<I>(i: I)
+   |    ^    ----
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hygiene/auxiliary/def-site-async-await.rs b/src/test/ui/hygiene/auxiliary/def-site-async-await.rs
new file mode 100644
index 0000000..f7e9b80
--- /dev/null
+++ b/src/test/ui/hygiene/auxiliary/def-site-async-await.rs
@@ -0,0 +1,7 @@
+// edition:2018
+
+extern crate opaque_hygiene;
+
+pub async fn serve() {
+    opaque_hygiene::make_it!();
+}
diff --git a/src/test/ui/hygiene/auxiliary/opaque-hygiene.rs b/src/test/ui/hygiene/auxiliary/opaque-hygiene.rs
new file mode 100644
index 0000000..7730f91
--- /dev/null
+++ b/src/test/ui/hygiene/auxiliary/opaque-hygiene.rs
@@ -0,0 +1,21 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::{TokenStream, quote};
+
+#[proc_macro]
+pub fn make_it(input: TokenStream) -> TokenStream {
+    // `quote!` applies def-site hygiene
+    quote! {
+        trait Foo {
+            fn my_fn(&self) {}
+        }
+
+        impl<T> Foo for T {}
+        "a".my_fn();
+    }
+}
diff --git a/src/test/ui/hygiene/generic_params.stderr b/src/test/ui/hygiene/generic_params.stderr
index 4ca6d19..6de36de 100644
--- a/src/test/ui/hygiene/generic_params.stderr
+++ b/src/test/ui/hygiene/generic_params.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/hygiene/issue-61574-const-parameters.stderr b/src/test/ui/hygiene/issue-61574-const-parameters.stderr
index b351b8b..3f85383 100644
--- a/src/test/ui/hygiene/issue-61574-const-parameters.stderr
+++ b/src/test/ui/hygiene/issue-61574-const-parameters.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/hygiene/issue-77523-def-site-async-await.rs b/src/test/ui/hygiene/issue-77523-def-site-async-await.rs
new file mode 100644
index 0000000..2af60ff
--- /dev/null
+++ b/src/test/ui/hygiene/issue-77523-def-site-async-await.rs
@@ -0,0 +1,19 @@
+// build-pass
+// aux-build:opaque-hygiene.rs
+// aux-build:def-site-async-await.rs
+
+// Regression test for issue #77523
+// Tests that we don't ICE when an unusual combination
+// of def-site hygiene and cross-crate monomorphization occurs.
+
+extern crate def_site_async_await;
+
+use std::future::Future;
+
+fn mk_ctxt() -> std::task::Context<'static> {
+    panic!()
+}
+
+fn main() {
+    Box::pin(def_site_async_await::serve()).as_mut().poll(&mut mk_ctxt());
+}
diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
index f31b752..02ddc39 100644
--- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr
@@ -3,6 +3,9 @@
    |
 LL |         print!();
    |         ^^^^^
+   |
+   = note: consider importing this macro:
+           std::print
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr
index 3c0c045..843dee2 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude.stderr
@@ -4,6 +4,9 @@
 LL |         assert_eq!(0, 0);
    |         ^^^^^^^^^^^^^^^^^
    |
+   = note: consider importing one of these items:
+           core::panic
+           std::panic
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0433]: failed to resolve: use of undeclared type `Vec`
diff --git a/src/test/ui/ifmt.rs b/src/test/ui/ifmt.rs
deleted file mode 100644
index 27ab3d6..0000000
--- a/src/test/ui/ifmt.rs
+++ /dev/null
@@ -1,319 +0,0 @@
-// run-pass
-
-#![deny(warnings)]
-#![allow(unused_must_use)]
-#![allow(unused_features)]
-#![feature(box_syntax)]
-
-use std::cell::RefCell;
-use std::fmt::{self, Write};
-use std::usize;
-
-struct A;
-struct B;
-struct C;
-struct D;
-
-impl fmt::LowerHex for A {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str("aloha")
-    }
-}
-impl fmt::UpperHex for B {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str("adios")
-    }
-}
-impl fmt::Display for C {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.pad_integral(true, "☃", "123")
-    }
-}
-impl fmt::Binary for D {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str("aa")?;
-        f.write_char('☃')?;
-        f.write_str("bb")
-    }
-}
-
-macro_rules! t {
-    ($a:expr, $b:expr) => { assert_eq!($a, $b) }
-}
-
-pub fn main() {
-    // Various edge cases without formats
-    t!(format!(""), "");
-    t!(format!("hello"), "hello");
-    t!(format!("hello {{"), "hello {");
-
-    // default formatters should work
-    t!(format!("{}", 1.0f32), "1");
-    t!(format!("{}", 1.0f64), "1");
-    t!(format!("{}", "a"), "a");
-    t!(format!("{}", "a".to_string()), "a");
-    t!(format!("{}", false), "false");
-    t!(format!("{}", 'a'), "a");
-
-    // At least exercise all the formats
-    t!(format!("{}", true), "true");
-    t!(format!("{}", '☃'), "☃");
-    t!(format!("{}", 10), "10");
-    t!(format!("{}", 10_usize), "10");
-    t!(format!("{:?}", '☃'), "'☃'");
-    t!(format!("{:?}", 10), "10");
-    t!(format!("{:?}", 10_usize), "10");
-    t!(format!("{:?}", "true"), "\"true\"");
-    t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
-    t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
-       r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#);
-    t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"),
-       r#""foo\u{0}bar\u{1}baz\u{7f}qux""#);
-    t!(format!("{:o}", 10_usize), "12");
-    t!(format!("{:x}", 10_usize), "a");
-    t!(format!("{:X}", 10_usize), "A");
-    t!(format!("{}", "foo"), "foo");
-    t!(format!("{}", "foo".to_string()), "foo");
-    if cfg!(target_pointer_width = "32") {
-        t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
-        t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
-    } else {
-        t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
-        t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
-    }
-    t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
-    t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
-    t!(format!("{:x}", A), "aloha");
-    t!(format!("{:X}", B), "adios");
-    t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
-    t!(format!("{1} {0}", 0, 1), "1 0");
-    t!(format!("{foo} {bar}", foo=0, bar=1), "0 1");
-    t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
-    t!(format!("{} {0}", "a"), "a a");
-    t!(format!("{_foo}", _foo = 6usize), "6");
-    t!(format!("{foo_bar}", foo_bar=1), "1");
-    t!(format!("{}", 5 + 5), "10");
-    t!(format!("{:#4}", C), "☃123");
-    t!(format!("{:b}", D), "aa☃bb");
-
-    let a: &dyn fmt::Debug = &1;
-    t!(format!("{:?}", a), "1");
-
-    // Formatting strings and their arguments
-    t!(format!("{}", "a"), "a");
-    t!(format!("{:4}", "a"), "a   ");
-    t!(format!("{:4}", "☃"), "☃   ");
-    t!(format!("{:>4}", "a"), "   a");
-    t!(format!("{:<4}", "a"), "a   ");
-    t!(format!("{:^5}", "a"),  "  a  ");
-    t!(format!("{:^5}", "aa"), " aa  ");
-    t!(format!("{:^4}", "a"),  " a  ");
-    t!(format!("{:^4}", "aa"), " aa ");
-    t!(format!("{:.4}", "a"), "a");
-    t!(format!("{:4.4}", "a"), "a   ");
-    t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "      aaaa");
-    t!(format!("{:2.4}", "aaaaa"), "aaaa");
-    t!(format!("{:2.4}", "aaaa"), "aaaa");
-    t!(format!("{:2.4}", "aaa"), "aaa");
-    t!(format!("{:2.4}", "aa"), "aa");
-    t!(format!("{:2.4}", "a"), "a ");
-    t!(format!("{:0>2}", "a"), "0a");
-    t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
-    t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
-    t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa");
-    t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a=4), "aaaa");
-    t!(format!("{:1$}", "a", 4), "a   ");
-    t!(format!("{1:0$}", 4, "a"), "a   ");
-    t!(format!("{:a$}", "a", a=4), "a   ");
-    t!(format!("{:-#}", "a"), "a");
-    t!(format!("{:+#}", "a"), "a");
-    t!(format!("{:/^10.8}", "1234567890"), "/12345678/");
-
-    // Some float stuff
-    t!(format!("{:}", 1.0f32), "1");
-    t!(format!("{:}", 1.0f64), "1");
-    t!(format!("{:.3}", 1.0f64), "1.000");
-    t!(format!("{:10.3}", 1.0f64),   "     1.000");
-    t!(format!("{:+10.3}", 1.0f64),  "    +1.000");
-    t!(format!("{:+10.3}", -1.0f64), "    -1.000");
-
-    t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
-    t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
-    t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
-    t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
-    t!(format!("{:10.3e}", 1.2345e6f64),   "   1.234e6");
-    t!(format!("{:+10.3e}", 1.2345e6f64),  "  +1.234e6");
-    t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");
-
-    // Float edge cases
-    t!(format!("{}", -0.0), "0");
-    t!(format!("{:?}", -0.0), "-0.0");
-    t!(format!("{:?}", 0.0), "0.0");
-
-    // sign aware zero padding
-    t!(format!("{:<3}", 1), "1  ");
-    t!(format!("{:>3}", 1), "  1");
-    t!(format!("{:^3}", 1), " 1 ");
-    t!(format!("{:03}", 1), "001");
-    t!(format!("{:<03}", 1), "001");
-    t!(format!("{:>03}", 1), "001");
-    t!(format!("{:^03}", 1), "001");
-    t!(format!("{:+03}", 1), "+01");
-    t!(format!("{:<+03}", 1), "+01");
-    t!(format!("{:>+03}", 1), "+01");
-    t!(format!("{:^+03}", 1), "+01");
-    t!(format!("{:#05x}", 1), "0x001");
-    t!(format!("{:<#05x}", 1), "0x001");
-    t!(format!("{:>#05x}", 1), "0x001");
-    t!(format!("{:^#05x}", 1), "0x001");
-    t!(format!("{:05}", 1.2), "001.2");
-    t!(format!("{:<05}", 1.2), "001.2");
-    t!(format!("{:>05}", 1.2), "001.2");
-    t!(format!("{:^05}", 1.2), "001.2");
-    t!(format!("{:05}", -1.2), "-01.2");
-    t!(format!("{:<05}", -1.2), "-01.2");
-    t!(format!("{:>05}", -1.2), "-01.2");
-    t!(format!("{:^05}", -1.2), "-01.2");
-    t!(format!("{:+05}", 1.2), "+01.2");
-    t!(format!("{:<+05}", 1.2), "+01.2");
-    t!(format!("{:>+05}", 1.2), "+01.2");
-    t!(format!("{:^+05}", 1.2), "+01.2");
-
-    // Ergonomic format_args!
-    t!(format!("{0:x} {0:X}", 15), "f F");
-    t!(format!("{0:x} {0:X} {}", 15), "f F 15");
-    t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a=15), "dDfEeF");
-    t!(format!("{a:x} {a:X}", a=15), "f F");
-
-    // And its edge cases
-    t!(format!("{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}",
-               4, a="abcdefg", b="hijklmn", c=3),
-               "abcd hijk 4\nabc hij 3");
-    t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a="abcdef"), "abcd 4 efg");
-    t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a=2), "aa 2 0x2");
-
-    // Test that pointers don't get truncated.
-    {
-        let val = usize::MAX;
-        let exp = format!("{:#x}", val);
-        t!(format!("{:p}", val as *const isize), exp);
-    }
-
-    // Escaping
-    t!(format!("{{"), "{");
-    t!(format!("}}"), "}");
-
-    test_write();
-    test_print();
-    test_order();
-    test_once();
-
-    // make sure that format! doesn't move out of local variables
-    let a: Box<_> = box 3;
-    format!("{}", a);
-    format!("{}", a);
-
-    // make sure that format! doesn't cause spurious unused-unsafe warnings when
-    // it's inside of an outer unsafe block
-    unsafe {
-        let a: isize = ::std::mem::transmute(3_usize);
-        format!("{}", a);
-    }
-
-    test_format_args();
-
-    // test that trailing commas are acceptable
-    format!("{}", "test",);
-    format!("{foo}", foo="test",);
-
-    test_refcell();
-}
-
-// Basic test to make sure that we can invoke the `write!` macro with an
-// fmt::Write instance.
-fn test_write() {
-    let mut buf = String::new();
-    write!(&mut buf, "{}", 3);
-    {
-        let w = &mut buf;
-        write!(w, "{foo}", foo=4);
-        write!(w, "{}", "hello");
-        writeln!(w, "{}", "line");
-        writeln!(w, "{foo}", foo="bar");
-        w.write_char('☃');
-        w.write_str("str");
-    }
-
-    t!(buf, "34helloline\nbar\n☃str");
-}
-
-// Just make sure that the macros are defined, there's not really a lot that we
-// can do with them just yet (to test the output)
-fn test_print() {
-    print!("hi");
-    print!("{:?}", vec![0u8]);
-    println!("hello");
-    println!("this is a {}", "test");
-    println!("{foo}", foo="bar");
-}
-
-// Just make sure that the macros are defined, there's not really a lot that we
-// can do with them just yet (to test the output)
-fn test_format_args() {
-    let mut buf = String::new();
-    {
-        let w = &mut buf;
-        write!(w, "{}", format_args!("{}", 1));
-        write!(w, "{}", format_args!("test"));
-        write!(w, "{}", format_args!("{test}", test=3));
-    }
-    let s = buf;
-    t!(s, "1test3");
-
-    let s = fmt::format(format_args!("hello {}", "world"));
-    t!(s, "hello world");
-    let s = format!("{}: {}", "args were", format_args!("hello {}", "world"));
-    t!(s, "args were: hello world");
-}
-
-fn test_order() {
-    // Make sure format!() arguments are always evaluated in a left-to-right
-    // ordering
-    fn foo() -> isize {
-        static mut FOO: isize = 0;
-        unsafe {
-            FOO += 1;
-            FOO
-        }
-    }
-    assert_eq!(format!("{} {} {a} {b} {} {c}",
-                       foo(), foo(), foo(), a=foo(), b=foo(), c=foo()),
-               "1 2 4 5 3 6".to_string());
-}
-
-fn test_once() {
-    // Make sure each argument are evaluated only once even though it may be
-    // formatted multiple times
-    fn foo() -> isize {
-        static mut FOO: isize = 0;
-        unsafe {
-            FOO += 1;
-            FOO
-        }
-    }
-    assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a=foo()),
-               "1 1 1 2 2 2".to_string());
-}
-
-fn test_refcell() {
-    let refcell = RefCell::new(5);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
-    let borrow = refcell.borrow_mut();
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: <borrowed> }");
-    drop(borrow);
-    assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }");
-}
diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr
index 8bb05c8..6b2b824 100644
--- a/src/test/ui/impl-trait/auto-trait-leak2.stderr
+++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr
@@ -11,7 +11,7 @@
    |     ^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
    |
    = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
-   = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22 p:Rc<Cell<i32>>]`
+   = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]`
    = note: required because it appears within the type `impl Fn<(i32,)>`
 
 error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
@@ -27,7 +27,7 @@
    |               ------------ within this `impl Fn<(i32,)>`
    |
    = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
-   = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:Rc<Cell<i32>>]`
+   = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22]`
    = note: required because it appears within the type `impl Fn<(i32,)>`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index 03aba10..a7d06c7 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -15,7 +15,6 @@
    |
    = note:         expected type `()`
            found associated type `<T as impl_trait::Trait>::Assoc`
-   = note: the return type of a function must have a statically known size
 help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
    |
 LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
@@ -35,7 +34,6 @@
    |
    = note:         expected type `()`
            found associated type `<T as lifetimes::Trait<'static>>::Assoc`
-   = note: the return type of a function must have a statically known size
 help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
    |
 LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
diff --git a/src/test/ui/impl-trait/equality-rpass.stderr b/src/test/ui/impl-trait/equality-rpass.stderr
index 1abf05d..11eeceb 100644
--- a/src/test/ui/impl-trait/equality-rpass.stderr
+++ b/src/test/ui/impl-trait/equality-rpass.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index cdaa61a..536a472 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0308]: mismatched types
   --> $DIR/equality.rs:15:5
diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr
index 1780931..1443b76 100644
--- a/src/test/ui/impl-trait/equality2.stderr
+++ b/src/test/ui/impl-trait/equality2.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0308]: mismatched types
   --> $DIR/equality2.rs:25:18
diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs
index fafab8a..238f3fa 100644
--- a/src/test/ui/impl-trait/example-calendar.rs
+++ b/src/test/ui/impl-trait/example-calendar.rs
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-compare-mode-chalk
 
 #![feature(fn_traits,
            step_trait,
diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs
index 99ac461..a746ed0 100644
--- a/src/test/ui/impl-trait/issue-55872-1.rs
+++ b/src/test/ui/impl-trait/issue-55872-1.rs
@@ -1,8 +1,7 @@
 // ignore-tidy-linelength
 #![feature(type_alias_impl_trait)]
 
-pub trait Bar
-{
+pub trait Bar {
     type E: Copy;
 
     fn foo<T>() -> Self::E;
@@ -14,7 +13,8 @@
     //~^^ ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277]
 
     fn foo<T: Default>() -> Self::E {
-    //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+        //~| ERROR impl has stricter requirements than trait
         (S::default(), T::default())
     }
 }
diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr
index a9f7394..64c536c 100644
--- a/src/test/ui/impl-trait/issue-55872-1.stderr
+++ b/src/test/ui/impl-trait/issue-55872-1.stderr
@@ -1,39 +1,48 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/issue-55872-1.rs:15:5
+   |
+LL |     fn foo<T>() -> Self::E;
+   |     ----------------------- definition of `foo` from trait
+...
+LL |     fn foo<T: Default>() -> Self::E {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Default`
+
 error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)`
-  --> $DIR/issue-55872-1.rs:12:14
+  --> $DIR/issue-55872-1.rs:11:14
    |
 LL |     type E = impl Copy;
    |              ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
    |
    = note: required because it appears within the type `(S, T)`
-   = note: the return type of a function must have a statically known size
 help: consider further restricting this bound
    |
 LL | impl<S: Default + Copy> Bar for S {
    |                 ^^^^^^
 
 error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)`
-  --> $DIR/issue-55872-1.rs:12:14
+  --> $DIR/issue-55872-1.rs:11:14
    |
 LL |     type E = impl Copy;
    |              ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
    |
    = note: required because it appears within the type `(S, T)`
-   = note: the return type of a function must have a statically known size
 help: consider further restricting this bound
    |
 LL |     fn foo<T: Default + Copy>() -> Self::E {
    |                       ^^^^^^
 
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872-1.rs:16:37
+  --> $DIR/issue-55872-1.rs:15:37
    |
 LL |       fn foo<T: Default>() -> Self::E {
    |  _____________________________________^
 LL | |
+LL | |
 LL | |         (S::default(), T::default())
 LL | |     }
    | |_____^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0276, E0277.
+For more information about an error, try `rustc --explain E0276`.
diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs
index 7708576..ee09a66 100644
--- a/src/test/ui/impl-trait/issue-55872-2.rs
+++ b/src/test/ui/impl-trait/issue-55872-2.rs
@@ -1,5 +1,6 @@
 // edition:2018
 // ignore-tidy-linelength
+// ignore-compare-mode-chalk
 
 #![feature(type_alias_impl_trait)]
 
diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr
index 6da3704..f954ce9 100644
--- a/src/test/ui/impl-trait/issue-55872-2.stderr
+++ b/src/test/ui/impl-trait/issue-55872-2.stderr
@@ -1,13 +1,11 @@
 error[E0277]: the trait bound `impl Future: Copy` is not satisfied
-  --> $DIR/issue-55872-2.rs:13:14
+  --> $DIR/issue-55872-2.rs:14:14
    |
 LL |     type E = impl std::marker::Copy;
    |              ^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future`
-   |
-   = note: the return type of a function must have a statically known size
 
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872-2.rs:15:28
+  --> $DIR/issue-55872-2.rs:16:28
    |
 LL |       fn foo<T>() -> Self::E {
    |  ____________________________^
diff --git a/src/test/ui/impl-trait/issue-55872.rs b/src/test/ui/impl-trait/issue-55872.rs
index bc91aae..b12bfbc 100644
--- a/src/test/ui/impl-trait/issue-55872.rs
+++ b/src/test/ui/impl-trait/issue-55872.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-linelength
+// ignore-compare-mode-chalk
 #![feature(type_alias_impl_trait)]
 
 pub trait Bar {
diff --git a/src/test/ui/impl-trait/issue-55872.stderr b/src/test/ui/impl-trait/issue-55872.stderr
index 60654ec..41d7beb 100644
--- a/src/test/ui/impl-trait/issue-55872.stderr
+++ b/src/test/ui/impl-trait/issue-55872.stderr
@@ -1,5 +1,5 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872.rs:13:28
+  --> $DIR/issue-55872.rs:14:28
    |
 LL |       fn foo<T>() -> Self::E {
    |  ____________________________^
diff --git a/src/test/ui/impl-trait/issues/issue-65581.rs b/src/test/ui/impl-trait/issues/issue-65581.rs
new file mode 100644
index 0000000..af65b79
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-65581.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+#![allow(dead_code)]
+
+trait Trait1<T, U> {
+    fn f1(self) -> U;
+}
+
+trait Trait2 {
+    type T;
+    type U: Trait2<T = Self::T>;
+    fn f2(f: impl FnOnce(&Self::U));
+}
+
+fn f3<T: Trait2>() -> impl Trait1<T, T::T> {
+    Struct1
+}
+
+struct Struct1;
+
+impl<T: Trait2> Trait1<T, T::T> for Struct1 {
+    fn f1(self) -> T::T {
+        unimplemented!()
+    }
+}
+
+fn f4<T: Trait2>() {
+    T::f2(|_| {
+        f3::<T::U>().f1();
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issues/issue-70877.rs b/src/test/ui/impl-trait/issues/issue-70877.rs
new file mode 100644
index 0000000..a4a59f9
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-70877.rs
@@ -0,0 +1,38 @@
+#![feature(type_alias_impl_trait)]
+#![feature(impl_trait_in_bindings)]
+#![allow(incomplete_features)]
+
+type FooArg<'a> = &'a dyn ToString;
+type FooRet = impl std::fmt::Debug;
+
+type FooItem = Box<dyn Fn(FooArg) -> FooRet>;
+type Foo = impl Iterator<Item = FooItem>; //~ ERROR: type mismatch
+
+#[repr(C)]
+struct Bar(u8);
+
+impl Iterator for Bar {
+    type Item = FooItem;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(Box::new(quux))
+    }
+}
+
+fn quux(st: FooArg) -> FooRet {
+    Some(st.to_string())
+}
+
+fn ham() -> Foo {
+    Bar(1)
+}
+
+fn oof() -> impl std::fmt::Debug {
+    let mut bar = ham();
+    let func = bar.next().unwrap();
+    return func(&"oof");
+}
+
+fn main() {
+    let _ = oof();
+}
diff --git a/src/test/ui/impl-trait/issues/issue-70877.stderr b/src/test/ui/impl-trait/issues/issue-70877.stderr
new file mode 100644
index 0000000..3ef7087
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-70877.stderr
@@ -0,0 +1,15 @@
+error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
+  --> $DIR/issue-70877.rs:9:12
+   |
+LL | type FooRet = impl std::fmt::Debug;
+   |               -------------------- the expected opaque type
+...
+LL | type Foo = impl Iterator<Item = FooItem>;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option`
+   |
+   = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
+              found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
index 9df5188..2f3726b 100644
--- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
+++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
@@ -1,15 +1,21 @@
 error[E0038]: the trait `NotObjectSafe` cannot be made into an object
   --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:21:13
    |
+LL | fn car() -> dyn NotObjectSafe {
+   |             ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8
+   |
 LL | trait NotObjectSafe {
    |       ------------- this trait cannot be made into an object...
 LL |     fn foo() -> Self;
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL | fn car() -> dyn NotObjectSafe {
-   |             ^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+help: consider turning `foo` into a method by giving it a `&self` argument
    |
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn foo(&self) -> Self;
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() -> Self where Self: Sized;
    |                      ^^^^^^^^^^^^^^^^^
@@ -17,15 +23,21 @@
 error[E0038]: the trait `NotObjectSafe` cannot be made into an object
   --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:13
    |
+LL | fn cat() -> Box<dyn NotObjectSafe> {
+   |             ^^^^^^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8
+   |
 LL | trait NotObjectSafe {
    |       ------------- this trait cannot be made into an object...
 LL |     fn foo() -> Self;
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL | fn cat() -> Box<dyn NotObjectSafe> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+help: consider turning `foo` into a method by giving it a `&self` argument
    |
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn foo(&self) -> Self;
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() -> Self where Self: Sized;
    |                      ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
index 42e1341..0f89ec2 100644
--- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
+++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
@@ -54,7 +54,7 @@
 LL | /     move || {
 LL | |         x;
 LL | |     }
-   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]`
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:40:29
@@ -65,7 +65,7 @@
 LL | /     move || {
 LL | |         &x;
 LL | |     }
-   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]`
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:48:21
@@ -95,7 +95,7 @@
 LL | |         yield;
 LL | |         x;
 LL | |     }
-   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]`
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 {()}]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:67:35
diff --git a/src/test/ui/impl-trait/wf-eval-order.rs b/src/test/ui/impl-trait/wf-eval-order.rs
new file mode 100644
index 0000000..c7d6bb8
--- /dev/null
+++ b/src/test/ui/impl-trait/wf-eval-order.rs
@@ -0,0 +1,39 @@
+// Check that we handle evaluating `wf` predicates correctly.
+
+// check-pass
+
+struct X<T: B>(T)
+where
+    T::V: Clone;
+
+fn hide<T>(t: T) -> impl Sized {
+    t
+}
+
+trait A {
+    type U;
+}
+
+impl<T> A for T {
+    type U = T;
+}
+
+trait B {
+    type V;
+}
+
+impl<S: A<U = T>, T> B for S {
+    type V = T;
+}
+
+fn main() {
+    // Evaluating `typeof(x): Sized` requires
+    //
+    // - `wf(typeof(x))` because we use a projection candidate.
+    // - `<i32 as B>::V: Clone` because that's a bound on the trait.
+    // - `<i32 as B>::V` normalizes to `_#1` where `<i32 as A>::U == _#1`
+    //
+    // This all works if we evaluate `<i32 as A>::U == _#1` before
+    // `<i32 as B>::V`, but we previously had the opposite order.
+    let x = hide(X(0));
+}
diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs
index 211a14e..72b880f 100644
--- a/src/test/ui/impl-trait/where-allowed.rs
+++ b/src/test/ui/impl-trait/where-allowed.rs
@@ -56,10 +56,12 @@
 fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
 //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
 //~| ERROR nested `impl Trait` is not allowed
+//~| ERROR cannot resolve opaque type
 
 // Disallowed
 fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
 //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+//~| ERROR cannot resolve opaque type
 
 // Disallowed
 fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }
diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr
index 7addc00..93f9724 100644
--- a/src/test/ui/impl-trait/where-allowed.stderr
+++ b/src/test/ui/impl-trait/where-allowed.stderr
@@ -17,7 +17,7 @@
    |                                                 outer `impl Trait`
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/where-allowed.rs:119:16
+  --> $DIR/where-allowed.rs:121:16
    |
 LL |     type Out = impl Debug;
    |                ^^^^^^^^^^
@@ -26,7 +26,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/where-allowed.rs:155:23
+  --> $DIR/where-allowed.rs:157:23
    |
 LL | type InTypeAlias<R> = impl Debug;
    |                       ^^^^^^^^^^
@@ -35,7 +35,7 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/where-allowed.rs:159:39
+  --> $DIR/where-allowed.rs:161:39
    |
 LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
    |                                       ^^^^^^^^^^
@@ -110,139 +110,139 @@
    |                                                         ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:61:59
+  --> $DIR/where-allowed.rs:62:59
    |
 LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
    |                                                           ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:65:38
+  --> $DIR/where-allowed.rs:67:38
    |
 LL | fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }
    |                                      ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:69:40
+  --> $DIR/where-allowed.rs:71:40
    |
 LL | fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() }
    |                                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:82:32
+  --> $DIR/where-allowed.rs:84:32
    |
 LL | struct InBraceStructField { x: impl Debug }
    |                                ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:86:41
+  --> $DIR/where-allowed.rs:88:41
    |
 LL | struct InAdtInBraceStructField { x: Vec<impl Debug> }
    |                                         ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:90:27
+  --> $DIR/where-allowed.rs:92:27
    |
 LL | struct InTupleStructField(impl Debug);
    |                           ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:95:25
+  --> $DIR/where-allowed.rs:97:25
    |
 LL |     InBraceVariant { x: impl Debug },
    |                         ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:97:20
+  --> $DIR/where-allowed.rs:99:20
    |
 LL |     InTupleVariant(impl Debug),
    |                    ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:108:23
+  --> $DIR/where-allowed.rs:110:23
    |
 LL |     fn in_return() -> impl Debug;
    |                       ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:126:34
+  --> $DIR/where-allowed.rs:128:34
    |
 LL |     fn in_trait_impl_return() -> impl Debug { () }
    |                                  ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:139:33
+  --> $DIR/where-allowed.rs:141:33
    |
 LL |     fn in_foreign_parameters(_: impl Debug);
    |                                 ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:142:31
+  --> $DIR/where-allowed.rs:144:31
    |
 LL |     fn in_foreign_return() -> impl Debug;
    |                               ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:159:39
+  --> $DIR/where-allowed.rs:161:39
    |
 LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
    |                                       ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:164:16
+  --> $DIR/where-allowed.rs:166:16
    |
 LL | impl PartialEq<impl Debug> for () {
    |                ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:169:24
+  --> $DIR/where-allowed.rs:171:24
    |
 LL | impl PartialEq<()> for impl Debug {
    |                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:174:6
+  --> $DIR/where-allowed.rs:176:6
    |
 LL | impl impl Debug {
    |      ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:180:24
+  --> $DIR/where-allowed.rs:182:24
    |
 LL | impl InInherentImplAdt<impl Debug> {
    |                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:186:11
+  --> $DIR/where-allowed.rs:188:11
    |
 LL |     where impl Debug: Debug
    |           ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:193:15
+  --> $DIR/where-allowed.rs:195:15
    |
 LL |     where Vec<impl Debug>: Debug
    |               ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:200:24
+  --> $DIR/where-allowed.rs:202:24
    |
 LL |     where T: PartialEq<impl Debug>
    |                        ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:207:17
+  --> $DIR/where-allowed.rs:209:17
    |
 LL |     where T: Fn(impl Debug)
    |                 ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:214:22
+  --> $DIR/where-allowed.rs:216:22
    |
 LL |     where T: Fn() -> impl Debug
    |                      ^^^^^^^^^^
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:220:29
+  --> $DIR/where-allowed.rs:222:29
    |
 LL |     let _in_local_variable: impl Fn() = || {};
    |                             ^^^^^^^^^
@@ -250,24 +250,44 @@
    = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
-  --> $DIR/where-allowed.rs:222:46
+  --> $DIR/where-allowed.rs:224:46
    |
 LL |     let _in_return_in_local_variable = || -> impl Fn() { || {} };
    |                                              ^^^^^^^^^
 
+error[E0720]: cannot resolve opaque type
+  --> $DIR/where-allowed.rs:56:49
+   |
+LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
+   |                                                 ^^^^^^^^^^^^^^^^^^^   -------- this returned value is of `!` type
+   |                                                 |
+   |                                                 cannot resolve opaque type
+   |
+   = help: this error will resolve once the item's body returns a concrete type
+
+error[E0720]: cannot resolve opaque type
+  --> $DIR/where-allowed.rs:62:46
+   |
+LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^   -------- this returned value is of `!` type
+   |                                              |
+   |                                              cannot resolve opaque type
+   |
+   = help: this error will resolve once the item's body returns a concrete type
+
 error: could not find defining uses
-  --> $DIR/where-allowed.rs:119:16
+  --> $DIR/where-allowed.rs:121:16
    |
 LL |     type Out = impl Debug;
    |                ^^^^^^^^^^
 
 error: could not find defining uses
-  --> $DIR/where-allowed.rs:155:23
+  --> $DIR/where-allowed.rs:157:23
    |
 LL | type InTypeAlias<R> = impl Debug;
    |                       ^^^^^^^^^^
 
-error: aborting due to 42 previous errors
+error: aborting due to 44 previous errors
 
-Some errors have detailed explanations: E0562, E0658, E0666.
+Some errors have detailed explanations: E0562, E0658, E0666, E0720.
 For more information about an error, try `rustc --explain E0562`.
diff --git a/src/test/ui/imports/issue-62767.rs b/src/test/ui/imports/issue-62767.rs
index 984d3f0..0e0f915 100644
--- a/src/test/ui/imports/issue-62767.rs
+++ b/src/test/ui/imports/issue-62767.rs
@@ -1,5 +1,4 @@
-// check-pass
-
+// Minimized case from #62767.
 mod m {
     pub enum Same {
         Same,
@@ -8,8 +7,22 @@
 
 use m::*;
 
-// The variant `Same` introduced by this import is not considered when resolving the prefix
-// `Same::` during import validation (issue #62767).
-use Same::Same;
+// The variant `Same` introduced by this import is also considered when resolving the prefix
+// `Same::` during import validation to avoid effects similar to time travel (#74556).
+use Same::Same; //~ ERROR unresolved import `Same`
+
+// Case from #74556.
+mod foo {
+    pub mod bar {
+        pub mod bar {
+            pub fn foobar() {}
+        }
+    }
+}
+
+use foo::*;
+use bar::bar; //~ ERROR unresolved import `bar::bar`
+              //~| ERROR inconsistent resolution for an import
+use bar::foobar;
 
 fn main() {}
diff --git a/src/test/ui/imports/issue-62767.stderr b/src/test/ui/imports/issue-62767.stderr
new file mode 100644
index 0000000..a4334bd
--- /dev/null
+++ b/src/test/ui/imports/issue-62767.stderr
@@ -0,0 +1,21 @@
+error: inconsistent resolution for an import
+  --> $DIR/issue-62767.rs:24:5
+   |
+LL | use bar::bar;
+   |     ^^^^^^^^
+
+error[E0432]: unresolved import `Same`
+  --> $DIR/issue-62767.rs:12:5
+   |
+LL | use Same::Same;
+   |     ^^^^ `Same` is a variant, not a module
+
+error[E0432]: unresolved import `bar::bar`
+  --> $DIR/issue-62767.rs:24:5
+   |
+LL | use bar::bar;
+   |     ^^^^^^^^ no `bar` in `foo::bar::bar`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr
index 31fcd4b..3152dec 100644
--- a/src/test/ui/indexing-requires-a-uint.stderr
+++ b/src/test/ui/indexing-requires-a-uint.stderr
@@ -13,7 +13,7 @@
 LL |     bar::<isize>(i);  // i should not be re-coerced back to an isize
    |                  ^ expected `isize`, found `usize`
    |
-help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     bar::<isize>(i.try_into().unwrap());  // i should not be re-coerced back to an isize
    |                  ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
index b6e3bb1..2f630c2 100644
--- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
+++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
@@ -8,12 +8,12 @@
    = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error[E0282]: type annotations needed for `impl Future`
-  --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:9
+  --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20
    |
 LL |     let fut = async {
    |         --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified
 LL |         make_unit()?;
-   |         ^^^^^^^^^^^^ cannot infer type
+   |                    ^ cannot infer type
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/inference/cannot-infer-async.stderr b/src/test/ui/inference/cannot-infer-async.stderr
index bf31fb8..92a9045 100644
--- a/src/test/ui/inference/cannot-infer-async.stderr
+++ b/src/test/ui/inference/cannot-infer-async.stderr
@@ -1,10 +1,10 @@
 error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-async.rs:11:9
+  --> $DIR/cannot-infer-async.rs:11:20
    |
 LL |     let fut = async {
    |         --- consider giving `fut` a type
 LL |         make_unit()?;
-   |         ^^^^^^^^^^^^ cannot infer type
+   |                    ^ cannot infer type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure.stderr b/src/test/ui/inference/cannot-infer-closure.stderr
index c26c24f..d5366e4 100644
--- a/src/test/ui/inference/cannot-infer-closure.stderr
+++ b/src/test/ui/inference/cannot-infer-closure.stderr
@@ -1,8 +1,8 @@
 error[E0282]: type annotations needed for the closure `fn((), ()) -> std::result::Result<(), _>`
-  --> $DIR/cannot-infer-closure.rs:3:9
+  --> $DIR/cannot-infer-closure.rs:3:15
    |
 LL |         Err(a)?;
-   |         ^^^^^^^ cannot infer type
+   |               ^ cannot infer type
    |
 help: give this closure an explicit return type without `_` placeholders
    |
diff --git a/src/test/ui/inference/issue-71732.rs b/src/test/ui/inference/issue-71732.rs
new file mode 100644
index 0000000..30063a0
--- /dev/null
+++ b/src/test/ui/inference/issue-71732.rs
@@ -0,0 +1,23 @@
+// Regression test for #71732, it used to emit incorrect diagnostics, like:
+// error[E0283]: type annotations needed
+//  --> src/main.rs:5:10
+//   |
+// 5 |         .get(&"key".into())
+//   |          ^^^ cannot infer type for struct `String`
+//   |
+//   = note: cannot satisfy `String: Borrow<_>`
+// help: consider specifying the type argument in the method call
+//   |
+// 5 |         .get::<Q>(&"key".into())
+//   |
+
+use std::collections::hash_map::HashMap;
+
+fn foo(parameters: &HashMap<String, String>) -> bool {
+    parameters
+        .get(&"key".into()) //~ ERROR: type annotations needed
+        .and_then(|found: &String| Some(false))
+        .unwrap_or(false)
+}
+
+fn main() {}
diff --git a/src/test/ui/inference/issue-71732.stderr b/src/test/ui/inference/issue-71732.stderr
new file mode 100644
index 0000000..17fad57
--- /dev/null
+++ b/src/test/ui/inference/issue-71732.stderr
@@ -0,0 +1,13 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-71732.rs:18:10
+   |
+LL |         .get(&"key".into())
+   |          ^^^  ------------ this method call resolves to `T`
+   |          |
+   |          cannot infer type for type parameter `Q` declared on the associated function `get`
+   |
+   = note: cannot satisfy `String: Borrow<_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/inference/issue-72616.rs b/src/test/ui/inference/issue-72616.rs
new file mode 100644
index 0000000..5e5a3ba
--- /dev/null
+++ b/src/test/ui/inference/issue-72616.rs
@@ -0,0 +1,29 @@
+// Regression test for #72616, it used to emit incorrect diagnostics, like:
+// error[E0283]: type annotations needed for `String`
+//  --> src/main.rs:8:30
+//   |
+// 5 |         let _: String = "".to_owned().try_into().unwrap();
+//   |             - consider giving this pattern a type
+// ...
+// 8 |         if String::from("a") == "a".try_into().unwrap() {}
+//   |                              ^^ cannot infer type for struct `String`
+//   |
+//   = note: cannot satisfy `String: PartialEq<_>`
+
+use std::convert::TryInto;
+
+pub fn main() {
+    {
+        let _: String = "".to_owned().try_into().unwrap();
+    }
+    {
+        if String::from("a") == "a".try_into().unwrap() {}
+        //~^ ERROR: type annotations needed
+    }
+    {
+        let _: String = match "_".try_into() {
+            Ok(a) => a,
+            Err(_) => "".into(),
+        };
+    }
+}
diff --git a/src/test/ui/inference/issue-72616.stderr b/src/test/ui/inference/issue-72616.stderr
new file mode 100644
index 0000000..d811988
--- /dev/null
+++ b/src/test/ui/inference/issue-72616.stderr
@@ -0,0 +1,13 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-72616.rs:20:30
+   |
+LL |         if String::from("a") == "a".try_into().unwrap() {}
+   |                              ^^ -------------- this method call resolves to `std::result::Result<T, <Self as TryInto<T>>::Error>`
+   |                              |
+   |                              cannot infer type
+   |
+   = note: cannot satisfy `String: PartialEq<_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/inline-const/const-expr-array-init.rs b/src/test/ui/inline-const/const-expr-array-init.rs
new file mode 100644
index 0000000..8bb5dab
--- /dev/null
+++ b/src/test/ui/inline-const/const-expr-array-init.rs
@@ -0,0 +1,10 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+
+use std::cell::Cell;
+
+fn main() {
+    let _x = [const { Cell::new(0) }; 20];
+}
diff --git a/src/test/ui/inline-const/const-expr-basic.rs b/src/test/ui/inline-const/const-expr-basic.rs
new file mode 100644
index 0000000..9254c96
--- /dev/null
+++ b/src/test/ui/inline-const/const-expr-basic.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+fn foo() -> i32 {
+    const {
+        let x = 5 + 10;
+        x / 3
+    }
+}
+
+fn main() {
+    assert_eq!(5, foo());
+}
diff --git a/src/test/ui/inline-const/const-expr-macro.rs b/src/test/ui/inline-const/const-expr-macro.rs
new file mode 100644
index 0000000..66b5857
--- /dev/null
+++ b/src/test/ui/inline-const/const-expr-macro.rs
@@ -0,0 +1,12 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+macro_rules! do_const_block{
+    ($val:block) => { const $val }
+}
+
+fn main() {
+    let s = do_const_block!({ 22 });
+    assert_eq!(s, 22);
+}
diff --git a/src/test/ui/inline-const/const-expr-reference.rs b/src/test/ui/inline-const/const-expr-reference.rs
new file mode 100644
index 0000000..747f14e
--- /dev/null
+++ b/src/test/ui/inline-const/const-expr-reference.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+
+const fn bar() -> i32 {
+    const {
+        2 + 3
+    }
+}
+
+fn main() {
+    let x: &'static i32 = &const{bar()};
+    assert_eq!(&5, x);
+}
diff --git a/src/test/ui/inline-const/const-match-pat-range.rs b/src/test/ui/inline-const/const-match-pat-range.rs
new file mode 100644
index 0000000..eefe43a
--- /dev/null
+++ b/src/test/ui/inline-const/const-match-pat-range.rs
@@ -0,0 +1,38 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(inline_const, half_open_range_patterns, exclusive_range_pattern)]
+fn main() {
+    const N: u32 = 10;
+    let x: u32 = 3;
+
+    match x {
+        1 ..= const { N + 1 } => {},
+        _ => {},
+    }
+
+    match x {
+        const { N - 1 } ..= 10 => {},
+        _ => {},
+    }
+
+    match x {
+        const { N - 1 } ..= const { N + 1 } => {},
+        _ => {},
+    }
+
+    match x {
+        .. const { N + 1 } => {},
+        _ => {},
+    }
+
+    match x {
+        const { N - 1 } .. => {},
+        _ => {},
+    }
+
+    match x {
+        ..= const { N + 1 } => {},
+        _ => {}
+    }
+}
diff --git a/src/test/ui/inline-const/const-match-pat.rs b/src/test/ui/inline-const/const-match-pat.rs
new file mode 100644
index 0000000..c0dc90d
--- /dev/null
+++ b/src/test/ui/inline-const/const-match-pat.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+const MMIO_BIT1: u8 = 4;
+const MMIO_BIT2: u8 = 5;
+
+fn main() {
+    let s = match read_mmio() {
+        0 => "FOO",
+        const { 1 << MMIO_BIT1 } => "BAR",
+        const { 1 << MMIO_BIT2 } => "BAZ",
+        _ => unreachable!(),
+    };
+
+    assert_eq!("BAZ", s);
+}
+
+fn read_mmio() -> i32 {
+    1 << 5
+}
diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr
index b850276..bfb4751 100644
--- a/src/test/ui/integer-literal-suffix-inference.stderr
+++ b/src/test/ui/integer-literal-suffix-inference.stderr
@@ -4,7 +4,7 @@
 LL |     id_i8(a16);
    |           ^^^ expected `i8`, found `i16`
    |
-help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     id_i8(a16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@
 LL |     id_i8(a32);
    |           ^^^ expected `i8`, found `i32`
    |
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     id_i8(a32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@
 LL |     id_i8(a64);
    |           ^^^ expected `i8`, found `i64`
    |
-help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     id_i8(a64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@
 LL |     id_i8(asize);
    |           ^^^^^ expected `i8`, found `isize`
    |
-help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     id_i8(asize.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@
    |            ^^
    |            |
    |            expected `i16`, found `i8`
-   |            help: you can convert an `i8` to `i16`: `a8.into()`
+   |            help: you can convert an `i8` to an `i16`: `a8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:55:12
@@ -57,7 +57,7 @@
 LL |     id_i16(a32);
    |            ^^^ expected `i16`, found `i32`
    |
-help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     id_i16(a32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@
 LL |     id_i16(a64);
    |            ^^^ expected `i16`, found `i64`
    |
-help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     id_i16(a64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -79,7 +79,7 @@
 LL |     id_i16(asize);
    |            ^^^^^ expected `i16`, found `isize`
    |
-help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     id_i16(asize.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -91,7 +91,7 @@
    |            ^^
    |            |
    |            expected `i32`, found `i8`
-   |            help: you can convert an `i8` to `i32`: `a8.into()`
+   |            help: you can convert an `i8` to an `i32`: `a8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:68:12
@@ -100,7 +100,7 @@
    |            ^^^
    |            |
    |            expected `i32`, found `i16`
-   |            help: you can convert an `i16` to `i32`: `a16.into()`
+   |            help: you can convert an `i16` to an `i32`: `a16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:72:12
@@ -108,7 +108,7 @@
 LL |     id_i32(a64);
    |            ^^^ expected `i32`, found `i64`
    |
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     id_i32(a64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -119,7 +119,7 @@
 LL |     id_i32(asize);
    |            ^^^^^ expected `i32`, found `isize`
    |
-help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     id_i32(asize.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@
    |            ^^
    |            |
    |            expected `i64`, found `i8`
-   |            help: you can convert an `i8` to `i64`: `a8.into()`
+   |            help: you can convert an `i8` to an `i64`: `a8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:82:12
@@ -140,7 +140,7 @@
    |            ^^^
    |            |
    |            expected `i64`, found `i16`
-   |            help: you can convert an `i16` to `i64`: `a16.into()`
+   |            help: you can convert an `i16` to an `i64`: `a16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:85:12
@@ -149,7 +149,7 @@
    |            ^^^
    |            |
    |            expected `i64`, found `i32`
-   |            help: you can convert an `i32` to `i64`: `a32.into()`
+   |            help: you can convert an `i32` to an `i64`: `a32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:89:12
@@ -157,7 +157,7 @@
 LL |     id_i64(asize);
    |            ^^^^^ expected `i64`, found `isize`
    |
-help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit
    |
 LL |     id_i64(asize.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@
    |              ^^
    |              |
    |              expected `isize`, found `i8`
-   |              help: you can convert an `i8` to `isize`: `a8.into()`
+   |              help: you can convert an `i8` to an `isize`: `a8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:96:14
@@ -178,7 +178,7 @@
    |              ^^^
    |              |
    |              expected `isize`, found `i16`
-   |              help: you can convert an `i16` to `isize`: `a16.into()`
+   |              help: you can convert an `i16` to an `isize`: `a16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:99:14
@@ -186,7 +186,7 @@
 LL |     id_isize(a32);
    |              ^^^ expected `isize`, found `i32`
    |
-help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     id_isize(a32.try_into().unwrap());
    |              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -197,7 +197,7 @@
 LL |     id_isize(a64);
    |              ^^^ expected `isize`, found `i64`
    |
-help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     id_isize(a64.try_into().unwrap());
    |              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -208,7 +208,7 @@
 LL |     id_i8(c16);
    |           ^^^ expected `i8`, found `i16`
    |
-help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     id_i8(c16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -219,7 +219,7 @@
 LL |     id_i8(c32);
    |           ^^^ expected `i8`, found `i32`
    |
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     id_i8(c32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -230,7 +230,7 @@
 LL |     id_i8(c64);
    |           ^^^ expected `i8`, found `i64`
    |
-help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     id_i8(c64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -242,7 +242,7 @@
    |            ^^
    |            |
    |            expected `i16`, found `i8`
-   |            help: you can convert an `i8` to `i16`: `c8.into()`
+   |            help: you can convert an `i8` to an `i16`: `c8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:122:12
@@ -250,7 +250,7 @@
 LL |     id_i16(c32);
    |            ^^^ expected `i16`, found `i32`
    |
-help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     id_i16(c32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -261,7 +261,7 @@
 LL |     id_i16(c64);
    |            ^^^ expected `i16`, found `i64`
    |
-help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     id_i16(c64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -273,7 +273,7 @@
    |            ^^
    |            |
    |            expected `i32`, found `i8`
-   |            help: you can convert an `i8` to `i32`: `c8.into()`
+   |            help: you can convert an `i8` to an `i32`: `c8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:132:12
@@ -282,7 +282,7 @@
    |            ^^^
    |            |
    |            expected `i32`, found `i16`
-   |            help: you can convert an `i16` to `i32`: `c16.into()`
+   |            help: you can convert an `i16` to an `i32`: `c16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:136:12
@@ -290,7 +290,7 @@
 LL |     id_i32(c64);
    |            ^^^ expected `i32`, found `i64`
    |
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     id_i32(c64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -302,7 +302,7 @@
    |            ^^
    |            |
    |            expected `i64`, found `i8`
-   |            help: you can convert an `i8` to `i64`: `a8.into()`
+   |            help: you can convert an `i8` to an `i64`: `a8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:143:12
@@ -311,7 +311,7 @@
    |            ^^^
    |            |
    |            expected `i64`, found `i16`
-   |            help: you can convert an `i16` to `i64`: `a16.into()`
+   |            help: you can convert an `i16` to an `i64`: `a16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:146:12
@@ -320,7 +320,7 @@
    |            ^^^
    |            |
    |            expected `i64`, found `i32`
-   |            help: you can convert an `i32` to `i64`: `a32.into()`
+   |            help: you can convert an `i32` to an `i64`: `a32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:152:11
@@ -328,7 +328,7 @@
 LL |     id_u8(b16);
    |           ^^^ expected `u8`, found `u16`
    |
-help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     id_u8(b16.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -339,7 +339,7 @@
 LL |     id_u8(b32);
    |           ^^^ expected `u8`, found `u32`
    |
-help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     id_u8(b32.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -350,7 +350,7 @@
 LL |     id_u8(b64);
    |           ^^^ expected `u8`, found `u64`
    |
-help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     id_u8(b64.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^
@@ -361,7 +361,7 @@
 LL |     id_u8(bsize);
    |           ^^^^^ expected `u8`, found `usize`
    |
-help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     id_u8(bsize.try_into().unwrap());
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -373,7 +373,7 @@
    |            ^^
    |            |
    |            expected `u16`, found `u8`
-   |            help: you can convert an `u8` to `u16`: `b8.into()`
+   |            help: you can convert a `u8` to a `u16`: `b8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:169:12
@@ -381,7 +381,7 @@
 LL |     id_u16(b32);
    |            ^^^ expected `u16`, found `u32`
    |
-help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     id_u16(b32.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -392,7 +392,7 @@
 LL |     id_u16(b64);
    |            ^^^ expected `u16`, found `u64`
    |
-help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     id_u16(b64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -403,7 +403,7 @@
 LL |     id_u16(bsize);
    |            ^^^^^ expected `u16`, found `usize`
    |
-help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     id_u16(bsize.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -415,7 +415,7 @@
    |            ^^
    |            |
    |            expected `u32`, found `u8`
-   |            help: you can convert an `u8` to `u32`: `b8.into()`
+   |            help: you can convert a `u8` to a `u32`: `b8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:182:12
@@ -424,7 +424,7 @@
    |            ^^^
    |            |
    |            expected `u32`, found `u16`
-   |            help: you can convert an `u16` to `u32`: `b16.into()`
+   |            help: you can convert a `u16` to a `u32`: `b16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:186:12
@@ -432,7 +432,7 @@
 LL |     id_u32(b64);
    |            ^^^ expected `u32`, found `u64`
    |
-help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     id_u32(b64.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -443,7 +443,7 @@
 LL |     id_u32(bsize);
    |            ^^^^^ expected `u32`, found `usize`
    |
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     id_u32(bsize.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -455,7 +455,7 @@
    |            ^^
    |            |
    |            expected `u64`, found `u8`
-   |            help: you can convert an `u8` to `u64`: `b8.into()`
+   |            help: you can convert a `u8` to a `u64`: `b8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:196:12
@@ -464,7 +464,7 @@
    |            ^^^
    |            |
    |            expected `u64`, found `u16`
-   |            help: you can convert an `u16` to `u64`: `b16.into()`
+   |            help: you can convert a `u16` to a `u64`: `b16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:199:12
@@ -473,7 +473,7 @@
    |            ^^^
    |            |
    |            expected `u64`, found `u32`
-   |            help: you can convert an `u32` to `u64`: `b32.into()`
+   |            help: you can convert a `u32` to a `u64`: `b32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:203:12
@@ -481,7 +481,7 @@
 LL |     id_u64(bsize);
    |            ^^^^^ expected `u64`, found `usize`
    |
-help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
    |
 LL |     id_u64(bsize.try_into().unwrap());
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -493,7 +493,7 @@
    |              ^^
    |              |
    |              expected `usize`, found `u8`
-   |              help: you can convert an `u8` to `usize`: `b8.into()`
+   |              help: you can convert a `u8` to a `usize`: `b8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:210:14
@@ -502,7 +502,7 @@
    |              ^^^
    |              |
    |              expected `usize`, found `u16`
-   |              help: you can convert an `u16` to `usize`: `b16.into()`
+   |              help: you can convert a `u16` to a `usize`: `b16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/integer-literal-suffix-inference.rs:213:14
@@ -510,7 +510,7 @@
 LL |     id_usize(b32);
    |              ^^^ expected `usize`, found `u32`
    |
-help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     id_usize(b32.try_into().unwrap());
    |              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -521,7 +521,7 @@
 LL |     id_usize(b64);
    |              ^^^ expected `usize`, found `u64`
    |
-help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     id_usize(b64.try_into().unwrap());
    |              ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr
index 3e19746..dd43da1 100644
--- a/src/test/ui/interior-mutability/interior-mutability.stderr
+++ b/src/test/ui/interior-mutability/interior-mutability.stderr
@@ -12,7 +12,7 @@
    = help: within `Cell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
    = note: required because it appears within the type `Cell<i32>`
    = note: required because of the requirements on the impl of `UnwindSafe` for `&Cell<i32>`
-   = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35 x:&Cell<i32>]`
+   = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.rs b/src/test/ui/invalid-rustc_args_required_const-arguments.rs
new file mode 100644
index 0000000..76c01c2
--- /dev/null
+++ b/src/test/ui/invalid-rustc_args_required_const-arguments.rs
@@ -0,0 +1,26 @@
+#![feature(rustc_attrs)]
+
+#[rustc_args_required_const(0)] //~ ERROR index exceeds number of arguments
+fn foo1() {}
+
+#[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments
+fn foo2(_: u8) {}
+
+#[rustc_args_required_const(a)] //~ ERROR arguments should be non-negative integers
+fn foo4() {}
+
+#[rustc_args_required_const(1, a, 2, b)] //~ ERROR arguments should be non-negative integers
+fn foo5(_: u8, _: u8, _: u8) {}
+
+#[rustc_args_required_const(0)] //~ ERROR attribute should be applied to a function
+struct S;
+
+#[rustc_args_required_const(0usize)] //~ ERROR suffixed literals are not allowed in attributes
+fn foo6(_: u8) {}
+
+extern {
+    #[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments
+    fn foo7(_: u8);
+}
+
+fn main() {}
diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr
new file mode 100644
index 0000000..39d0462
--- /dev/null
+++ b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr
@@ -0,0 +1,48 @@
+error: suffixed literals are not allowed in attributes
+  --> $DIR/invalid-rustc_args_required_const-arguments.rs:18:29
+   |
+LL | #[rustc_args_required_const(0usize)]
+   |                             ^^^^^^
+   |
+   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
+
+error: index exceeds number of arguments
+  --> $DIR/invalid-rustc_args_required_const-arguments.rs:3:29
+   |
+LL | #[rustc_args_required_const(0)]
+   |                             ^ there are only 0 arguments
+
+error: index exceeds number of arguments
+  --> $DIR/invalid-rustc_args_required_const-arguments.rs:6:29
+   |
+LL | #[rustc_args_required_const(1)]
+   |                             ^ there is only 1 argument
+
+error: arguments should be non-negative integers
+  --> $DIR/invalid-rustc_args_required_const-arguments.rs:9:29
+   |
+LL | #[rustc_args_required_const(a)]
+   |                             ^
+
+error: arguments should be non-negative integers
+  --> $DIR/invalid-rustc_args_required_const-arguments.rs:12:32
+   |
+LL | #[rustc_args_required_const(1, a, 2, b)]
+   |                                ^     ^
+
+error: attribute should be applied to a function
+  --> $DIR/invalid-rustc_args_required_const-arguments.rs:15:1
+   |
+LL | #[rustc_args_required_const(0)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | struct S;
+   | --------- not a function
+
+error: index exceeds number of arguments
+  --> $DIR/invalid-rustc_args_required_const-arguments.rs:22:33
+   |
+LL |     #[rustc_args_required_const(1)]
+   |                                 ^ there is only 1 argument
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/issue-72470-llvm-dominate.rs b/src/test/ui/issue-72470-llvm-dominate.rs
new file mode 100644
index 0000000..5bb69a0
--- /dev/null
+++ b/src/test/ui/issue-72470-llvm-dominate.rs
@@ -0,0 +1,66 @@
+// compile-flags: -C opt-level=3
+// aux-build: issue-72470-lib.rs
+// edition:2018
+// build-pass
+
+// Regression test for issue #72470, using the minimization
+// in https://github.com/jonas-schievink/llvm-error
+
+extern crate issue_72470_lib;
+
+use std::future::Future;
+use std::pin::Pin;
+use std::sync::Mutex;
+use std::task::Poll::{Pending, Ready};
+
+#[allow(dead_code)]
+enum Msg {
+    A(Vec<()>),
+    B,
+}
+
+#[allow(dead_code)]
+enum Out {
+    _0(Option<Msg>),
+    Disabled,
+}
+
+#[allow(unused_must_use)]
+fn main() {
+    let mut rx = issue_72470_lib::unbounded_channel::<Msg>();
+    let entity = Mutex::new(());
+    issue_72470_lib::run(async move {
+        {
+            let output = {
+                let mut fut = rx.recv();
+                issue_72470_lib::poll_fn(|cx| {
+                    loop {
+                        let fut = unsafe { Pin::new_unchecked(&mut fut) };
+                        let out = match fut.poll(cx) {
+                            Ready(out) => out,
+                            Pending => {
+                                break;
+                            }
+                        };
+                        #[allow(unused_variables)]
+                        match &out {
+                            Some(_msg) => {}
+                            _ => break,
+                        }
+                        return Ready(Out::_0(out));
+                    }
+                    Ready(Out::_0(None))
+                })
+                .await
+            };
+            match output {
+                Out::_0(Some(_msg)) => {
+                    entity.lock();
+                }
+                Out::_0(None) => unreachable!(),
+                _ => unreachable!(),
+            }
+        }
+        entity.lock();
+    });
+}
diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr
index 867f8f0..bbcdd3e 100644
--- a/src/test/ui/issues-71798.stderr
+++ b/src/test/ui/issues-71798.stderr
@@ -9,11 +9,8 @@
    |
 LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
-LL |     *x
-   |     -- this returned value is of type `u32`
    |
    = help: the trait `Future` is not implemented for `u32`
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr
index e5ac85a..e1559ab 100644
--- a/src/test/ui/issues/issue-12127.stderr
+++ b/src/test/ui/issues/issue-12127.stderr
@@ -11,7 +11,7 @@
    |
 LL |         f();
    |         ^
-   = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41 x:Box<isize>]`, which does not implement the `Copy` trait
+   = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41]`, which does not implement the `Copy` trait
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr
index 68258a8..115b471 100644
--- a/src/test/ui/issues/issue-13359.stderr
+++ b/src/test/ui/issues/issue-13359.stderr
@@ -4,7 +4,7 @@
 LL |     foo(1*(1 as isize));
    |         ^^^^^^^^^^^^^^ expected `i16`, found `isize`
    |
-help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo((1*(1 as isize)).try_into().unwrap());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@
 LL |     bar(1*(1 as usize));
    |         ^^^^^^^^^^^^^^ expected `u32`, found `usize`
    |
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     bar((1*(1 as usize)).try_into().unwrap());
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-18075.rs b/src/test/ui/issues/issue-18075.rs
deleted file mode 100644
index 56ec629..0000000
--- a/src/test/ui/issues/issue-18075.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// run-pass
-// rustc-env:RUSTC_LOG=rustc::middle=debug
-
-fn main() {
-    let b = 1isize;
-    println!("{}", b);
-}
diff --git a/src/test/ui/issues/issue-18389.stderr b/src/test/ui/issues/issue-18389.stderr
index 090487e..dc476f5 100644
--- a/src/test/ui/issues/issue-18389.stderr
+++ b/src/test/ui/issues/issue-18389.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-18389.rs:7:1
    |
 LL |   trait Private<P, R> {
-   |   - `Private<<Self as Public>::P, <Self as Public>::R>` declared as private
+   |   ------------------- `Private<<Self as Public>::P, <Self as Public>::R>` declared as private
 ...
 LL | / pub trait Public: Private<
 LL | |
diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr
index a952c9b..b10d26a 100644
--- a/src/test/ui/issues/issue-18819.stderr
+++ b/src/test/ui/issues/issue-18819.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/issue-18819.rs:16:5
    |
-LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) {
-   | ----------------------------------------------- defined here
-...
 LL |     print_x(X);
    |     ^^^^^^^ - supplied 1 argument
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/issue-18819.rs:11:4
+   |
+LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) {
+   |    ^^^^^^^ ----------------------  -----------
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-18959.stderr b/src/test/ui/issues/issue-18959.stderr
index b3ba7ae..86b530e 100644
--- a/src/test/ui/issues/issue-18959.stderr
+++ b/src/test/ui/issues/issue-18959.stderr
@@ -1,15 +1,17 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/issue-18959.rs:11:11
    |
-LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
-   |                    --- ...because method `foo` has generic type parameters
-LL | pub trait Bar: Foo { }
-   |           --- this trait cannot be made into an object...
-...
 LL | fn foo(b: &dyn Bar) {
-   |           ^^^^^^^^ the trait `Bar` cannot be made into an object
+   |           ^^^^^^^^ `Bar` cannot be made into an object
    |
    = help: consider moving `foo` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-18959.rs:1:20
+   |
+LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); }
+   |                    ^^^ ...because method `foo` has generic type parameters
+LL | pub trait Bar: Foo { }
+   |           --- this trait cannot be made into an object...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19380.stderr b/src/test/ui/issues/issue-19380.stderr
index 63f0701..c3a5d3d 100644
--- a/src/test/ui/issues/issue-19380.stderr
+++ b/src/test/ui/issues/issue-19380.stderr
@@ -1,15 +1,21 @@
 error[E0038]: the trait `Qiz` cannot be made into an object
   --> $DIR/issue-19380.rs:11:9
    |
+LL |   foos: &'static [&'static (dyn Qiz + 'static)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Qiz` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-19380.rs:2:6
+   |
 LL | trait Qiz {
    |       --- this trait cannot be made into an object...
 LL |   fn qiz();
-   |      --- ...because associated function `qiz` has no `self` parameter
-...
-LL |   foos: &'static [&'static (dyn Qiz + 'static)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object
+   |      ^^^ ...because associated function `qiz` has no `self` parameter
+help: consider turning `qiz` into a method by giving it a `&self` argument
    |
-help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |   fn qiz(&self);
+   |          ^^^^^
+help: alternatively, consider constraining `qiz` so it does not apply to trait objects
    |
 LL |   fn qiz() where Self: Sized;
    |            ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr
index 71a0132..555d0ff 100644
--- a/src/test/ui/issues/issue-19538.stderr
+++ b/src/test/ui/issues/issue-19538.stderr
@@ -1,30 +1,34 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/issue-19538.rs:17:15
    |
+LL |     let test: &mut dyn Bar = &mut thing;
+   |               ^^^^^^^^^^^^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `foo` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-19538.rs:2:8
+   |
 LL |     fn foo<T>(&self, val: T);
-   |        --- ...because method `foo` has generic type parameters
+   |        ^^^ ...because method `foo` has generic type parameters
 ...
 LL | trait Bar: Foo { }
    |       --- this trait cannot be made into an object...
-...
-LL |     let test: &mut dyn Bar = &mut thing;
-   |               ^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `foo` to another trait
 
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/issue-19538.rs:17:30
    |
+LL |     let test: &mut dyn Bar = &mut thing;
+   |                              ^^^^^^^^^^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `foo` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-19538.rs:2:8
+   |
 LL |     fn foo<T>(&self, val: T);
-   |        --- ...because method `foo` has generic type parameters
+   |        ^^^ ...because method `foo` has generic type parameters
 ...
 LL | trait Bar: Foo { }
    |       --- this trait cannot be made into an object...
-...
-LL |     let test: &mut dyn Bar = &mut thing;
-   |                              ^^^^^^^^^^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `foo` to another trait
    = note: required because of the requirements on the impl of `CoerceUnsized<&mut dyn Bar>` for `&mut Thing`
    = note: required by cast to type `&mut dyn Bar`
 
diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr
index e8d16a5..9940f43 100644
--- a/src/test/ui/issues/issue-20605.stderr
+++ b/src/test/ui/issues/issue-20605.stderr
@@ -5,6 +5,7 @@
    |                 ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `dyn Iterator<Item = &'a mut u8>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator<Item = &'a mut u8>`
    = note: required by `into_iter`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr
index 0badf66..1d7f252 100644
--- a/src/test/ui/issues/issue-20692.stderr
+++ b/src/test/ui/issues/issue-20692.stderr
@@ -1,27 +1,32 @@
 error[E0038]: the trait `Array` cannot be made into an object
   --> $DIR/issue-20692.rs:7:5
    |
+LL |     &dyn Array;
+   |     ^^^^^^^^^^ `Array` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-20692.rs:1:14
+   |
 LL | trait Array: Sized + Copy {}
-   |       -----  -----   ---- ...because it requires `Self: Sized`
+   |       -----  ^^^^^   ^^^^ ...because it requires `Self: Sized`
    |       |      |
    |       |      ...because it requires `Self: Sized`
    |       this trait cannot be made into an object...
-...
-LL |     &dyn Array;
-   |     ^^^^^^^^^^ the trait `Array` cannot be made into an object
 
 error[E0038]: the trait `Array` cannot be made into an object
   --> $DIR/issue-20692.rs:4:13
    |
+LL |     let _ = x
+   |             ^ `Array` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-20692.rs:1:14
+   |
 LL | trait Array: Sized + Copy {}
-   |       -----  -----   ---- ...because it requires `Self: Sized`
+   |       -----  ^^^^^   ^^^^ ...because it requires `Self: Sized`
    |       |      |
    |       |      ...because it requires `Self: Sized`
    |       this trait cannot be made into an object...
-...
-LL |     let _ = x
-   |             ^ the trait `Array` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Array>` for `&T`
    = note: required by cast to type `&dyn Array`
 
diff --git a/src/test/ui/issues/issue-20831-debruijn.rs b/src/test/ui/issues/issue-20831-debruijn.rs
index d0e15cb..20d9807 100644
--- a/src/test/ui/issues/issue-20831-debruijn.rs
+++ b/src/test/ui/issues/issue-20831-debruijn.rs
@@ -28,9 +28,6 @@
     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
         // Not obvious, but there is an implicit lifetime here -------^
         //~^^ ERROR cannot infer
-        //~| ERROR cannot infer
-        //~| ERROR mismatched types
-        //~| ERROR mismatched types
         //
         // The fact that `Publisher` is using an implicit lifetime is
         // what was causing the debruijn accounting to be off, so
diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr
index 1ab89e8..bcfb6b7 100644
--- a/src/test/ui/issues/issue-20831-debruijn.stderr
+++ b/src/test/ui/issues/issue-20831-debruijn.stderr
@@ -1,53 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-20831-debruijn.rs:28:5
-   |
-LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-LL | |         // Not obvious, but there is an implicit lifetime here -------^
-LL | |
-LL | |
-...  |
-LL | |         self.sub = t;
-LL | |     }
-   | |_____^ lifetime mismatch
-   |
-   = note: expected type `'a`
-              found type `'_`
-note: the anonymous lifetime #2 defined on the method body at 28:5...
-  --> $DIR/issue-20831-debruijn.rs:28:5
-   |
-LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 26:6
-  --> $DIR/issue-20831-debruijn.rs:26:6
-   |
-LL | impl<'a> Publisher<'a> for MyStruct<'a> {
-   |      ^^
-
-error[E0308]: mismatched types
-  --> $DIR/issue-20831-debruijn.rs:28:5
-   |
-LL | /     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-LL | |         // Not obvious, but there is an implicit lifetime here -------^
-LL | |
-LL | |
-...  |
-LL | |         self.sub = t;
-LL | |     }
-   | |_____^ lifetime mismatch
-   |
-   = note: expected type `'a`
-              found type `'_`
-note: the lifetime `'a` as defined on the impl at 26:6...
-  --> $DIR/issue-20831-debruijn.rs:26:6
-   |
-LL | impl<'a> Publisher<'a> for MyStruct<'a> {
-   |      ^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the method body at 28:5
-  --> $DIR/issue-20831-debruijn.rs:28:5
-   |
-LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> $DIR/issue-20831-debruijn.rs:28:33
    |
@@ -72,31 +22,6 @@
    = note: expected `Publisher<'_>`
               found `Publisher<'_>`
 
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/issue-20831-debruijn.rs:28:33
-   |
-LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 28:5...
-  --> $DIR/issue-20831-debruijn.rs:28:5
-   |
-LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the impl at 26:6...
-  --> $DIR/issue-20831-debruijn.rs:26:6
-   |
-LL | impl<'a> Publisher<'a> for MyStruct<'a> {
-   |      ^^
-note: ...so that the types are compatible
-  --> $DIR/issue-20831-debruijn.rs:28:33
-   |
-LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: expected `Publisher<'_>`
-              found `Publisher<'_>`
+error: aborting due to previous error
 
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0308, E0495.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/issues/issue-21946.rs b/src/test/ui/issues/issue-21946.rs
index 0a9f8f5..d0c052c 100644
--- a/src/test/ui/issues/issue-21946.rs
+++ b/src/test/ui/issues/issue-21946.rs
@@ -5,7 +5,6 @@
 struct FooStruct;
 
 impl Foo for FooStruct {
-    //~^ ERROR overflow evaluating the requirement `<FooStruct as Foo>::A == _`
     type A = <FooStruct as Foo>::A;
     //~^ ERROR overflow evaluating the requirement `<FooStruct as Foo>::A == _`
 }
diff --git a/src/test/ui/issues/issue-21946.stderr b/src/test/ui/issues/issue-21946.stderr
index 582ce39..0497bd2 100644
--- a/src/test/ui/issues/issue-21946.stderr
+++ b/src/test/ui/issues/issue-21946.stderr
@@ -1,15 +1,9 @@
 error[E0275]: overflow evaluating the requirement `<FooStruct as Foo>::A == _`
-  --> $DIR/issue-21946.rs:7:6
-   |
-LL | impl Foo for FooStruct {
-   |      ^^^
-
-error[E0275]: overflow evaluating the requirement `<FooStruct as Foo>::A == _`
-  --> $DIR/issue-21946.rs:9:5
+  --> $DIR/issue-21946.rs:8:5
    |
 LL |     type A = <FooStruct as Foo>::A;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/issues/issue-23046.rs b/src/test/ui/issues/issue-23046.rs
index 75be4a1..a683696 100644
--- a/src/test/ui/issues/issue-23046.rs
+++ b/src/test/ui/issues/issue-23046.rs
@@ -14,7 +14,7 @@
 }
 
 fn main() {
-    let ex = |x| {
-        let_(add(x,x), |y| { //~ ERROR type annotations needed
+    let ex = |x| { //~ ERROR type annotations needed
+        let_(add(x,x), |y| {
             let_(add(x, x), |x|x)})};
 }
diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr
index 77555fc..12b2eb4 100644
--- a/src/test/ui/issues/issue-23046.stderr
+++ b/src/test/ui/issues/issue-23046.stderr
@@ -1,13 +1,8 @@
-error[E0282]: type annotations needed for the closure `fn(Expr<'_, _>) -> Expr<'_, _>`
-  --> $DIR/issue-23046.rs:18:9
+error[E0282]: type annotations needed for `Expr<'_, VAR>`
+  --> $DIR/issue-23046.rs:17:15
    |
-LL |         let_(add(x,x), |y| {
-   |         ^^^^ cannot infer type for type parameter `VAR` declared on the function `let_`
-   |
-help: give this closure an explicit return type without `_` placeholders
-   |
-LL |             let_(add(x, x), |x|-> Expr<'_, _> { x })})};
-   |                                ^^^^^^^^^^^^^^^^   ^
+LL |     let ex = |x| {
+   |               ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23122-1.rs b/src/test/ui/issues/issue-23122-1.rs
index d6f6465..efa4e61 100644
--- a/src/test/ui/issues/issue-23122-1.rs
+++ b/src/test/ui/issues/issue-23122-1.rs
@@ -1,3 +1,5 @@
+// ignore-compare-mode-chalk
+
 trait Next {
     type Next: Next;
 }
@@ -5,7 +7,6 @@
 struct GetNext<T: Next> { t: T }
 
 impl<T: Next> Next for GetNext<T> {
-    //~^ ERROR overflow evaluating the requirement
     type Next = <GetNext<T> as Next>::Next;
     //~^ ERROR overflow evaluating the requirement
 }
diff --git a/src/test/ui/issues/issue-23122-1.stderr b/src/test/ui/issues/issue-23122-1.stderr
index 4e2e837..8613c1e 100644
--- a/src/test/ui/issues/issue-23122-1.stderr
+++ b/src/test/ui/issues/issue-23122-1.stderr
@@ -1,15 +1,9 @@
 error[E0275]: overflow evaluating the requirement `<GetNext<T> as Next>::Next == _`
-  --> $DIR/issue-23122-1.rs:7:15
-   |
-LL | impl<T: Next> Next for GetNext<T> {
-   |               ^^^^
-
-error[E0275]: overflow evaluating the requirement `<GetNext<T> as Next>::Next == _`
-  --> $DIR/issue-23122-1.rs:9:5
+  --> $DIR/issue-23122-1.rs:10:5
    |
 LL |     type Next = <GetNext<T> as Next>::Next;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/issues/issue-23122-2.rs b/src/test/ui/issues/issue-23122-2.rs
index 695712d..7866b93 100644
--- a/src/test/ui/issues/issue-23122-2.rs
+++ b/src/test/ui/issues/issue-23122-2.rs
@@ -1,3 +1,4 @@
+// ignore-compare-mode-chalk
 trait Next {
     type Next: Next;
 }
@@ -5,7 +6,6 @@
 struct GetNext<T: Next> { t: T }
 
 impl<T: Next> Next for GetNext<T> {
-    //~^ ERROR overflow evaluating the requirement
     type Next = <GetNext<T::Next> as Next>::Next;
     //~^ ERROR overflow evaluating the requirement
 }
diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr
index 60dbb15..ce3bffe 100644
--- a/src/test/ui/issues/issue-23122-2.stderr
+++ b/src/test/ui/issues/issue-23122-2.stderr
@@ -1,12 +1,3 @@
-error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
-  --> $DIR/issue-23122-2.rs:7:15
-   |
-LL | impl<T: Next> Next for GetNext<T> {
-   |               ^^^^
-   |
-   = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`)
-   = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
-
 error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
   --> $DIR/issue-23122-2.rs:9:5
    |
@@ -16,6 +7,6 @@
    = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`)
    = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/issues/issue-24204.rs b/src/test/ui/issues/issue-24204.rs
index 61671b3..5a7b345 100644
--- a/src/test/ui/issues/issue-24204.rs
+++ b/src/test/ui/issues/issue-24204.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 #![allow(dead_code)]
 
 trait MultiDispatch<T> {
@@ -8,10 +10,16 @@
     type A: MultiDispatch<Self::B, O = Self>;
     type B;
 
-    fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O where Self::A : MultiDispatch<U>;
+    fn new<U>(u: U) -> <Self::A as MultiDispatch<U>>::O
+    where
+        Self::A: MultiDispatch<U>;
 }
 
-fn test<T: Trait<B=i32>>(b: i32) -> T where T::A: MultiDispatch<i32> { T::new(b) }
-//~^ ERROR type mismatch resolving
+fn test<T: Trait<B = i32>>(b: i32) -> T
+where
+    T::A: MultiDispatch<i32>,
+{
+    T::new(b)
+}
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-24204.stderr b/src/test/ui/issues/issue-24204.stderr
deleted file mode 100644
index d5cbcf7..0000000
--- a/src/test/ui/issues/issue-24204.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0271]: type mismatch resolving `<<T as Trait>::A as MultiDispatch<i32>>::O == T`
-  --> $DIR/issue-24204.rs:14:12
-   |
-LL | trait Trait: Sized {
-   |       ----- required by a bound in this
-LL |     type A: MultiDispatch<Self::B, O = Self>;
-   |                                    -------- required by this bound in `Trait`
-...
-LL | fn test<T: Trait<B=i32>>(b: i32) -> T where T::A: MultiDispatch<i32> { T::new(b) }
-   |         -  ^^^^^^^^^^^^ expected type parameter `T`, found associated type
-   |         |
-   |         this type parameter
-   |
-   = note: expected type parameter `T`
-             found associated type `<<T as Trait>::A as MultiDispatch<i32>>::O`
-   = note: you might be missing a type parameter or trait bound
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/issues/issue-26056.stderr b/src/test/ui/issues/issue-26056.stderr
index be438ef..2c87324 100644
--- a/src/test/ui/issues/issue-26056.stderr
+++ b/src/test/ui/issues/issue-26056.stderr
@@ -1,13 +1,16 @@
 error[E0038]: the trait `Map` cannot be made into an object
   --> $DIR/issue-26056.rs:20:13
    |
+LL |         as &dyn Map<Key=u32,MapValue=u32>;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-26056.rs:9:12
+   |
 LL | trait Map: MapLookup<<Self as Map>::Key> {
-   |       ---  ----------------------------- ...because it uses `Self` as a type parameter in this
+   |       ---  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
    |       this trait cannot be made into an object...
-...
-LL |         as &dyn Map<Key=u32,MapValue=u32>;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Map` cannot be made into an object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr
index 2038d88..a6f1ac9 100644
--- a/src/test/ui/issues/issue-26094.stderr
+++ b/src/test/ui/issues/issue-26094.stderr
@@ -4,11 +4,14 @@
 LL |         $other(None)
    |                ---- supplied 1 argument
 ...
-LL | fn some_function() {}
-   | ------------------ defined here
-...
 LL |     some_macro!(some_function);
    |                 ^^^^^^^^^^^^^ expected 0 arguments
+   |
+note: function defined here
+  --> $DIR/issue-26094.rs:7:4
+   |
+LL | fn some_function() {}
+   |    ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-28098.stderr b/src/test/ui/issues/issue-28098.stderr
index df552fc..4c927a0 100644
--- a/src/test/ui/issues/issue-28098.stderr
+++ b/src/test/ui/issues/issue-28098.stderr
@@ -14,6 +14,7 @@
    |              ^^^^^ `bool` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `bool`
+   = note: required because of the requirements on the impl of `IntoIterator` for `bool`
    = note: required by `into_iter`
 
 error[E0277]: `()` is not an iterator
@@ -58,6 +59,7 @@
    |              ^^^^^ `bool` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `bool`
+   = note: required because of the requirements on the impl of `IntoIterator` for `bool`
    = note: required by `into_iter`
 
 error[E0277]: `()` is not an iterator
diff --git a/src/test/ui/issues/issue-28561.rs b/src/test/ui/issues/issue-28561.rs
index 1241fb0..184f5cb 100644
--- a/src/test/ui/issues/issue-28561.rs
+++ b/src/test/ui/issues/issue-28561.rs
@@ -1,4 +1,5 @@
 // check-pass
+// ignore-compare-mode-chalk
 #[derive(Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
 struct Array<T> {
     f00: [T; 00],
diff --git a/src/test/ui/issues/issue-28576.stderr b/src/test/ui/issues/issue-28576.stderr
index 6581990..203cd06 100644
--- a/src/test/ui/issues/issue-28576.stderr
+++ b/src/test/ui/issues/issue-28576.stderr
@@ -1,16 +1,19 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/issue-28576.rs:7:12
    |
-LL |   pub trait Bar: Foo<Assoc=()> {
-   |             ---  -------------
-   |             |    |   |
-   |             |    |   ...because it uses `Self` as a type parameter in this
-   |             |    ...because it uses `Self` as a type parameter in this
-   |             this trait cannot be made into an object...
-LL |       fn new(&self, b: &
 LL | /            dyn Bar
 LL | |               <Assoc=()>
-   | |________________________^ the trait `Bar` cannot be made into an object
+   | |________________________^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-28576.rs:5:16
+   |
+LL | pub trait Bar: Foo<Assoc=()> {
+   |           ---  ^^^^^^^^^^^^^
+   |           |    |   |
+   |           |    |   ...because it uses `Self` as a type parameter
+   |           |    ...because it uses `Self` as a type parameter
+   |           this trait cannot be made into an object...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-28837.rs b/src/test/ui/issues/issue-28837.rs
index f874b00..9719c3a 100644
--- a/src/test/ui/issues/issue-28837.rs
+++ b/src/test/ui/issues/issue-28837.rs
@@ -7,7 +7,7 @@
 
     a - a; //~ ERROR cannot subtract `A` from `A`
 
-    a * a; //~ ERROR cannot multiply `A` to `A`
+    a * a; //~ ERROR cannot multiply `A` by `A`
 
     a / a; //~ ERROR cannot divide `A` by `A`
 
diff --git a/src/test/ui/issues/issue-28837.stderr b/src/test/ui/issues/issue-28837.stderr
index b63e168..07f67bc 100644
--- a/src/test/ui/issues/issue-28837.stderr
+++ b/src/test/ui/issues/issue-28837.stderr
@@ -18,7 +18,7 @@
    |
    = note: an implementation of `std::ops::Sub` might be missing for `A`
 
-error[E0369]: cannot multiply `A` to `A`
+error[E0369]: cannot multiply `A` by `A`
   --> $DIR/issue-28837.rs:10:7
    |
 LL |     a * a;
diff --git a/src/test/ui/issues/issue-30079.stderr b/src/test/ui/issues/issue-30079.stderr
index e67f297..e40b194 100644
--- a/src/test/ui/issues/issue-30079.stderr
+++ b/src/test/ui/issues/issue-30079.stderr
@@ -12,7 +12,7 @@
   --> $DIR/issue-30079.rs:18:9
    |
 LL |     struct Priv;
-   |     - `m2::Priv` declared as private
+   |     ------------ `m2::Priv` declared as private
 LL |     impl ::std::ops::Deref for ::SemiPriv {
 LL |         type Target = Priv;
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -21,7 +21,7 @@
   --> $DIR/issue-30079.rs:35:9
    |
 LL |     struct Priv;
-   |     - `m3::Priv` declared as private
+   |     ------------ `m3::Priv` declared as private
 LL |     impl ::SemiPrivTrait for () {
 LL |         type Assoc = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr
index a4f69a1..818e004 100644
--- a/src/test/ui/issues/issue-31173.stderr
+++ b/src/test/ui/issues/issue-31173.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as Iterator>::Item == &_`
+error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item == &_`
   --> $DIR/issue-31173.rs:10:10
    |
 LL |         .cloned()
@@ -7,11 +7,11 @@
    = note:   expected type `u8`
            found reference `&_`
 
-error[E0599]: no method named `collect` found for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope
+error[E0599]: no method named `collect` found for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` in the current scope
   --> $DIR/issue-31173.rs:14:10
    |
 LL |         .collect();
-   |          ^^^^^^^ method not found in `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>`
+   |          ^^^^^^^ method not found in `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>`
    | 
   ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL
    |
@@ -22,10 +22,10 @@
    | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
    |
    = note: the method `collect` exists but the following trait bounds were not satisfied:
-           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as Iterator>::Item = &_`
-           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: Iterator`
-           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: Iterator`
-           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: Iterator`
+           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item = &_`
+           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
+           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
+           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-33187.rs b/src/test/ui/issues/issue-33187.rs
index 5226f9f..f6b5661 100644
--- a/src/test/ui/issues/issue-33187.rs
+++ b/src/test/ui/issues/issue-33187.rs
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-compare-mode-chalk
 struct Foo<A: Repr>(<A as Repr>::Data);
 
 impl<A> Copy for Foo<A> where <A as Repr>::Data: Copy { }
diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr
index aeab923..e91dae0 100644
--- a/src/test/ui/issues/issue-33941.stderr
+++ b/src/test/ui/issues/issue-33941.stderr
@@ -16,6 +16,8 @@
    = note:  expected tuple `(&_, &_)`
            found reference `&_`
    = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
+   = note: required by `into_iter`
 
 error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
   --> $DIR/issue-33941.rs:4:14
@@ -26,6 +28,7 @@
    = note:  expected tuple `(&_, &_)`
            found reference `&_`
    = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
+   = note: required by `std::iter::Iterator::next`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/issues/issue-35376.stderr b/src/test/ui/issues/issue-35376.stderr
index 06c31f3..835277d 100644
--- a/src/test/ui/issues/issue-35376.stderr
+++ b/src/test/ui/issues/issue-35376.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/issues/issue-35668.rs b/src/test/ui/issues/issue-35668.rs
index 6f6dfb0..c970163 100644
--- a/src/test/ui/issues/issue-35668.rs
+++ b/src/test/ui/issues/issue-35668.rs
@@ -1,6 +1,6 @@
 fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> {
     a.iter().map(|a| a*a)
-    //~^ ERROR cannot multiply `&T` to `&T`
+    //~^ ERROR cannot multiply `&T` by `&T`
 }
 
 fn main() {
diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr
index 600cacc..81a2bb8 100644
--- a/src/test/ui/issues/issue-35668.stderr
+++ b/src/test/ui/issues/issue-35668.stderr
@@ -1,4 +1,4 @@
-error[E0369]: cannot multiply `&T` to `&T`
+error[E0369]: cannot multiply `&T` by `&T`
   --> $DIR/issue-35668.rs:2:23
    |
 LL |     a.iter().map(|a| a*a)
diff --git a/src/test/ui/issues/issue-37051.rs b/src/test/ui/issues/issue-37051.rs
index 9cae6cf..e0c4719 100644
--- a/src/test/ui/issues/issue-37051.rs
+++ b/src/test/ui/issues/issue-37051.rs
@@ -1,4 +1,5 @@
 // check-pass
+// ignore-compare-mode-chalk
 
 #![feature(associated_type_defaults)]
 
diff --git a/src/test/ui/issues/issue-37550.rs b/src/test/ui/issues/issue-37550.rs
index 505c030..35b63bd 100644
--- a/src/test/ui/issues/issue-37550.rs
+++ b/src/test/ui/issues/issue-37550.rs
@@ -1,6 +1,6 @@
 const fn x() {
     let t = true;
-    let x = || t; //~ ERROR function pointers in const fn are unstable
+    let x = || t; //~ ERROR function pointer
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-37550.stderr b/src/test/ui/issues/issue-37550.stderr
index 35da625..54b60df 100644
--- a/src/test/ui/issues/issue-37550.stderr
+++ b/src/test/ui/issues/issue-37550.stderr
@@ -1,12 +1,12 @@
-error[E0723]: function pointers in const fn are unstable
+error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/issue-37550.rs:3:9
    |
 LL |     let x = || t;
    |         ^
    |
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0723`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-38091.rs b/src/test/ui/issues/issue-38091.rs
deleted file mode 100644
index a84391b..0000000
--- a/src/test/ui/issues/issue-38091.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#![feature(specialization)]
-//~^ WARN the feature `specialization` is incomplete
-
-trait Iterate<'a> {
-    type Ty: Valid;
-    fn iterate(self);
-}
-impl<'a, T> Iterate<'a> for T where T: Check {
-    default type Ty = ();
-    //~^ ERROR the trait bound `(): Valid` is not satisfied
-    default fn iterate(self) {}
-}
-
-trait Check {}
-impl<'a, T> Check for T where <T as Iterate<'a>>::Ty: Valid {}
-
-trait Valid {}
-
-fn main() {
-    Iterate::iterate(0);
-}
diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr
deleted file mode 100644
index 81beec8..0000000
--- a/src/test/ui/issues/issue-38091.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-38091.rs:1:12
-   |
-LL | #![feature(specialization)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
-
-error[E0277]: the trait bound `(): Valid` is not satisfied
-  --> $DIR/issue-38091.rs:9:5
-   |
-LL |     type Ty: Valid;
-   |     --------------- required by `Iterate::Ty`
-...
-LL |     default type Ty = ();
-   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()`
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-3820.rs b/src/test/ui/issues/issue-3820.rs
index c090654..b987a90 100644
--- a/src/test/ui/issues/issue-3820.rs
+++ b/src/test/ui/issues/issue-3820.rs
@@ -11,5 +11,5 @@
 fn main() {
     let u = Thing {x: 2};
     let _v = u.mul(&3); // This is ok
-    let w = u * 3; //~ ERROR cannot multiply `{integer}` to `Thing`
+    let w = u * 3; //~ ERROR cannot multiply `Thing` by `{integer}`
 }
diff --git a/src/test/ui/issues/issue-3820.stderr b/src/test/ui/issues/issue-3820.stderr
index 8cc7682..84f8f9b 100644
--- a/src/test/ui/issues/issue-3820.stderr
+++ b/src/test/ui/issues/issue-3820.stderr
@@ -1,4 +1,4 @@
-error[E0369]: cannot multiply `{integer}` to `Thing`
+error[E0369]: cannot multiply `Thing` by `{integer}`
   --> $DIR/issue-3820.rs:14:15
    |
 LL |     let w = u * 3;
diff --git a/src/test/ui/issues/issue-38404.stderr b/src/test/ui/issues/issue-38404.stderr
index 50c5195..d7721d7 100644
--- a/src/test/ui/issues/issue-38404.stderr
+++ b/src/test/ui/issues/issue-38404.stderr
@@ -1,12 +1,16 @@
 error[E0038]: the trait `B` cannot be made into an object
   --> $DIR/issue-38404.rs:3:15
    |
+LL | trait C<T>: A<dyn B<T, Output=usize>> {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-38404.rs:1:13
+   |
 LL | trait A<T>: std::ops::Add<Self> + Sized {}
-   |             ------------------- ...because it uses `Self` as a type parameter in this
+   |             ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
 LL | trait B<T>: A<T> {}
    |       - this trait cannot be made into an object...
-LL | trait C<T>: A<dyn B<T, Output=usize>> {}
-   |               ^^^^^^^^^^^^^^^^^^^^^^ the trait `B` cannot be made into an object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr
index 39a62b8..d41488c 100644
--- a/src/test/ui/issues/issue-38604.stderr
+++ b/src/test/ui/issues/issue-38604.stderr
@@ -1,25 +1,30 @@
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/issue-38604.rs:14:13
    |
+LL |     let _f: Box<dyn Foo> =
+   |             ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-38604.rs:2:22
+   |
 LL | trait Foo where u32: Q<Self> {
-   |       ---            ------- ...because it uses `Self` as a type parameter in this
+   |       ---            ^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     let _f: Box<dyn Foo> =
-   |             ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/issue-38604.rs:15:9
    |
+LL |         Box::new(());
+   |         ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-38604.rs:2:22
+   |
 LL | trait Foo where u32: Q<Self> {
-   |       ---            ------- ...because it uses `Self` as a type parameter in this
+   |       ---            ^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
    |       this trait cannot be made into an object...
-...
-LL |         Box::new(());
-   |         ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Foo>>` for `Box<()>`
    = note: required by cast to type `Box<dyn Foo>`
 
diff --git a/src/test/ui/issues/issue-41139.rs b/src/test/ui/issues/issue-41139.rs
index 4814232..94c5321 100644
--- a/src/test/ui/issues/issue-41139.rs
+++ b/src/test/ui/issues/issue-41139.rs
@@ -1,8 +1,12 @@
 trait Trait {}
 
-fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait { panic!("") }
+fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait {
+    panic!("")
+}
 
 fn main() {
-    let t : &dyn Trait = &get_function()();
-    //~^ ERROR cannot move a value of type dyn Trait
+    // This isn't great. The issue here is that `dyn Trait` is not sized, so
+    // `dyn Fn() -> dyn Trait` is not well-formed.
+    let t: &dyn Trait = &get_function()();
+    //~^ ERROR expected function, found `&dyn Fn() -> (dyn Trait + 'static)`
 }
diff --git a/src/test/ui/issues/issue-41139.stderr b/src/test/ui/issues/issue-41139.stderr
index 829d0cf..48b22bc 100644
--- a/src/test/ui/issues/issue-41139.stderr
+++ b/src/test/ui/issues/issue-41139.stderr
@@ -1,9 +1,14 @@
-error[E0161]: cannot move a value of type dyn Trait: the size of dyn Trait cannot be statically determined
-  --> $DIR/issue-41139.rs:6:27
+error[E0618]: expected function, found `&dyn Fn() -> (dyn Trait + 'static)`
+  --> $DIR/issue-41139.rs:10:26
    |
-LL |     let t : &dyn Trait = &get_function()();
-   |                           ^^^^^^^^^^^^^^^^
+LL | fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait {
+   | -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)`
+...
+LL |     let t: &dyn Trait = &get_function()();
+   |                          ^^^^^^^^^^^^^^--
+   |                          |
+   |                          call expression requires function
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0161`.
+For more information about this error, try `rustc --explain E0618`.
diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr
index f134218..a092c94 100644
--- a/src/test/ui/issues/issue-41974.stderr
+++ b/src/test/ui/issues/issue-41974.stderr
@@ -21,7 +21,7 @@
 LL | impl<T> Drop for T where T: A {
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/issues/issue-43398.rs b/src/test/ui/issues/issue-43398.rs
index f0b762c..581db03 100644
--- a/src/test/ui/issues/issue-43398.rs
+++ b/src/test/ui/issues/issue-43398.rs
@@ -2,6 +2,7 @@
 
 #![feature(core_intrinsics)]
 #![feature(repr128)]
+//~^ WARN the feature `repr128` is incomplete
 
 #[repr(i128)]
 enum Big { A, B }
diff --git a/src/test/ui/issues/issue-43398.stderr b/src/test/ui/issues/issue-43398.stderr
new file mode 100644
index 0000000..9a39415
--- /dev/null
+++ b/src/test/ui/issues/issue-43398.stderr
@@ -0,0 +1,11 @@
+warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-43398.rs:4:12
+   |
+LL | #![feature(repr128)]
+   |            ^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #56071 <https://github.com/rust-lang/rust/issues/56071> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/issues/issue-43784-associated-type.stderr b/src/test/ui/issues/issue-43784-associated-type.stderr
index 039852a..d5105ae 100644
--- a/src/test/ui/issues/issue-43784-associated-type.stderr
+++ b/src/test/ui/issues/issue-43784-associated-type.stderr
@@ -1,8 +1,11 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-43784-associated-type.rs:14:18
+  --> $DIR/issue-43784-associated-type.rs:14:5
    |
+LL |     type Assoc: Partial<Self>;
+   |                 ------------- required by this bound in `Complete::Assoc`
+...
 LL |     type Assoc = T;
-   |                  ^ the trait `Copy` is not implemented for `T`
+   |     ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/issues/issue-43784-supertrait.stderr b/src/test/ui/issues/issue-43784-supertrait.stderr
index d92e4fa..c73536b 100644
--- a/src/test/ui/issues/issue-43784-supertrait.stderr
+++ b/src/test/ui/issues/issue-43784-supertrait.stderr
@@ -1,6 +1,9 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/issue-43784-supertrait.rs:8:9
    |
+LL | pub trait Complete: Partial {
+   |                     ------- required by this bound in `Complete`
+...
 LL | impl<T> Complete for T {}
    |         ^^^^^^^^ the trait `Copy` is not implemented for `T`
    |
diff --git a/src/test/ui/issues/issue-46553.rs b/src/test/ui/issues/issue-46553.rs
index e21a532..0a1e835 100644
--- a/src/test/ui/issues/issue-46553.rs
+++ b/src/test/ui/issues/issue-46553.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(const_fn)]
+#![feature(const_fn_fn_ptr_basics)]
 #![deny(const_err)]
 
 pub struct Data<T> {
diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr
index 0cc686e..03b9b91 100644
--- a/src/test/ui/issues/issue-4935.stderr
+++ b/src/test/ui/issues/issue-4935.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/issue-4935.rs:5:13
    |
-LL | fn foo(a: usize) {}
-   | ---------------- defined here
-LL |
 LL | fn main() { foo(5, 6) }
    |             ^^^ -  - supplied 2 arguments
    |             |
    |             expected 1 argument
+   |
+note: function defined here
+  --> $DIR/issue-4935.rs:3:4
+   |
+LL | fn foo(a: usize) {}
+   |    ^^^ --------
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-50301.rs b/src/test/ui/issues/issue-50301.rs
index 47ee3e7..4fcb414 100644
--- a/src/test/ui/issues/issue-50301.rs
+++ b/src/test/ui/issues/issue-50301.rs
@@ -1,5 +1,6 @@
 // Tests that HRTBs are correctly accepted -- https://github.com/rust-lang/rust/issues/50301
 // check-pass
+// ignore-compare-mode-chalk
 trait Trait
 where
     for<'a> &'a Self::IntoIter: IntoIterator<Item = u32>,
diff --git a/src/test/ui/issues/issue-50781.stderr b/src/test/ui/issues/issue-50781.stderr
index 03e3a7f..93bd951 100644
--- a/src/test/ui/issues/issue-50781.stderr
+++ b/src/test/ui/issues/issue-50781.stderr
@@ -1,10 +1,8 @@
 error: the trait `X` cannot be made into an object
   --> $DIR/issue-50781.rs:6:8
    |
-LL | trait X {
-   |       - this trait cannot be made into an object...
 LL |     fn foo(&self) where Self: Trait;
-   |        ^^^ ...because method `foo` references the `Self` type in its `where` clause
+   |        ^^^
    |
 note: the lint level is defined here
   --> $DIR/issue-50781.rs:1:9
@@ -13,6 +11,13 @@
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = 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 #51443 <https://github.com/rust-lang/rust/issues/51443>
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-50781.rs:6:8
+   |
+LL | trait X {
+   |       - this trait cannot be made into an object...
+LL |     fn foo(&self) where Self: Trait;
+   |        ^^^ ...because method `foo` references the `Self` type in its `where` clause
    = help: consider moving `foo` to another trait
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-50865-private-impl-trait/auxiliary/lib.rs b/src/test/ui/issues/issue-50865-private-impl-trait/auxiliary/lib.rs
index f3a51b4..fb4bf2b 100644
--- a/src/test/ui/issues/issue-50865-private-impl-trait/auxiliary/lib.rs
+++ b/src/test/ui/issues/issue-50865-private-impl-trait/auxiliary/lib.rs
@@ -1,3 +1,7 @@
+// revisions: default miropt
+//[miropt]compile-flags: -Z mir-opt-level=2
+// ~^ This flag is for #77668, it used to be ICE.
+
 #![crate_type = "lib"]
 
 pub fn bar<P>( // Error won't happen if "bar" is not generic
diff --git a/src/test/ui/issues/issue-5099.rs b/src/test/ui/issues/issue-5099.rs
index ee13483..b5abccb 100644
--- a/src/test/ui/issues/issue-5099.rs
+++ b/src/test/ui/issues/issue-5099.rs
@@ -5,6 +5,9 @@
     fn b(x: i32) {
         this.b(x); //~ ERROR cannot find value `this` in this scope
     }
+    fn c() {
+        let _ = || this.a; //~ ERROR cannot find value `this` in this scope
+    }
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-5099.stderr b/src/test/ui/issues/issue-5099.stderr
index b52fd28..b39c4a9 100644
--- a/src/test/ui/issues/issue-5099.stderr
+++ b/src/test/ui/issues/issue-5099.stderr
@@ -28,6 +28,21 @@
 LL |     fn b(&self, x: i32) {
    |          ^^^^^^
 
-error: aborting due to 2 previous errors
+error[E0425]: cannot find value `this` in this scope
+  --> $DIR/issue-5099.rs:9:20
+   |
+LL |         let _ = || this.a;
+   |                    ^^^^ not found in this scope
+   |
+help: you might have meant to use `self` here instead
+   |
+LL |         let _ = || self.a;
+   |                    ^^^^
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+   |
+LL |     fn c(&self) {
+   |          ^^^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/issues/issue-51154.rs b/src/test/ui/issues/issue-51154.rs
new file mode 100644
index 0000000..12903f7
--- /dev/null
+++ b/src/test/ui/issues/issue-51154.rs
@@ -0,0 +1,6 @@
+fn foo<F: FnMut()>() {
+    let _: Box<F> = Box::new(|| ());
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-51154.stderr b/src/test/ui/issues/issue-51154.stderr
new file mode 100644
index 0000000..3c3428f
--- /dev/null
+++ b/src/test/ui/issues/issue-51154.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-51154.rs:2:30
+   |
+LL | fn foo<F: FnMut()>() {
+   |        - this type parameter
+LL |     let _: Box<F> = Box::new(|| ());
+   |                              ^^^^^ expected type parameter `F`, found closure
+   |
+   = note: expected type parameter `F`
+                     found closure `[closure@$DIR/issue-51154.rs:2:30: 2:35]`
+   = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-54062.rs b/src/test/ui/issues/issue-54062.rs
index 60a9b00..093d660 100644
--- a/src/test/ui/issues/issue-54062.rs
+++ b/src/test/ui/issues/issue-54062.rs
@@ -7,7 +7,6 @@
 fn main() {}
 
 fn testing(test: Test) {
-    let _ = test.comps.inner.lock().unwrap();
+    let _ = test.comps.inner.try_lock();
     //~^ ERROR: field `inner` of struct `Mutex` is private
-    //~| ERROR: no method named `unwrap` found
 }
diff --git a/src/test/ui/issues/issue-54062.stderr b/src/test/ui/issues/issue-54062.stderr
index e9e8080..5361ee1 100644
--- a/src/test/ui/issues/issue-54062.stderr
+++ b/src/test/ui/issues/issue-54062.stderr
@@ -1,16 +1,9 @@
 error[E0616]: field `inner` of struct `Mutex` is private
   --> $DIR/issue-54062.rs:10:24
    |
-LL |     let _ = test.comps.inner.lock().unwrap();
+LL |     let _ = test.comps.inner.try_lock();
    |                        ^^^^^ private field
 
-error[E0599]: no method named `unwrap` found for struct `std::sys_common::mutex::MutexGuard<'_>` in the current scope
-  --> $DIR/issue-54062.rs:10:37
-   |
-LL |     let _ = test.comps.inner.lock().unwrap();
-   |                                     ^^^^^^ method not found in `std::sys_common::mutex::MutexGuard<'_>`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0599, E0616.
-For more information about an error, try `rustc --explain E0599`.
+For more information about this error, try `rustc --explain E0616`.
diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr
index 6b67125..eb85f34 100644
--- a/src/test/ui/issues/issue-54348.stderr
+++ b/src/test/ui/issues/issue-54348.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-54348.rs:5:5
    |
 LL |     [1][1.5 as usize];
-   |     ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |     ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -10,7 +10,7 @@
   --> $DIR/issue-54348.rs:6:5
    |
 LL |     [1][1u64 as usize];
-   |     ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+   |     ^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-55380.stderr b/src/test/ui/issues/issue-55380.stderr
index 451beeb..65e94d7 100644
--- a/src/test/ui/issues/issue-55380.stderr
+++ b/src/test/ui/issues/issue-55380.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/issues/issue-55796.nll.stderr b/src/test/ui/issues/issue-55796.nll.stderr
index baa0e6c..61d4070d 100644
--- a/src/test/ui/issues/issue-55796.nll.stderr
+++ b/src/test/ui/issues/issue-55796.nll.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-55796.rs:16:9
+  --> $DIR/issue-55796.rs:18:9
    |
 LL | pub trait Graph<'a> {
    |                 -- lifetime `'a` defined here
@@ -10,7 +10,7 @@
    = help: consider replacing `'a` with `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/issue-55796.rs:21:9
+  --> $DIR/issue-55796.rs:23:9
    |
 LL | pub trait Graph<'a> {
    |                 -- lifetime `'a` defined here
diff --git a/src/test/ui/issues/issue-55796.rs b/src/test/ui/issues/issue-55796.rs
index 088d430..1086669 100644
--- a/src/test/ui/issues/issue-55796.rs
+++ b/src/test/ui/issues/issue-55796.rs
@@ -1,3 +1,5 @@
+// ignore-compare-mode-chalk
+
 pub trait EdgeTrait<N> {
     fn target(&self) -> N;
 }
diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr
index 1aa0050..ffe3bb7 100644
--- a/src/test/ui/issues/issue-55796.stderr
+++ b/src/test/ui/issues/issue-55796.stderr
@@ -1,22 +1,22 @@
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-55796.rs:16:9
+  --> $DIR/issue-55796.rs:18:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 5:17...
-  --> $DIR/issue-55796.rs:5:17
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 7:17...
+  --> $DIR/issue-55796.rs:7:17
    |
 LL | pub trait Graph<'a> {
    |                 ^^
-note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds
-  --> $DIR/issue-55796.rs:16:9
+note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:18:40: 18:54]>` will meet its required lifetime bounds
+  --> $DIR/issue-55796.rs:18:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the expression is assignable
-  --> $DIR/issue-55796.rs:16:9
+  --> $DIR/issue-55796.rs:18:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,24 +24,24 @@
               found `Box<dyn Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-55796.rs:21:9
+  --> $DIR/issue-55796.rs:23:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 5:17...
-  --> $DIR/issue-55796.rs:5:17
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 7:17...
+  --> $DIR/issue-55796.rs:7:17
    |
 LL | pub trait Graph<'a> {
    |                 ^^
-note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds
-  --> $DIR/issue-55796.rs:21:9
+note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:23:39: 23:53]>` will meet its required lifetime bounds
+  --> $DIR/issue-55796.rs:23:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the expression is assignable
-  --> $DIR/issue-55796.rs:21:9
+  --> $DIR/issue-55796.rs:23:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-58344.rs b/src/test/ui/issues/issue-58344.rs
index 9b184e2..0cb04dc 100644
--- a/src/test/ui/issues/issue-58344.rs
+++ b/src/test/ui/issues/issue-58344.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 use std::ops::Add;
 
 trait Trait<T> {
@@ -18,7 +20,11 @@
 }
 
 impl<L, R> Either<L, R> {
-    fn converge<T>(self) -> T where L: Trait<T>, R: Trait<T> {
+    fn converge<T>(self) -> T
+    where
+        L: Trait<T>,
+        R: Trait<T>,
+    {
         match self {
             Either::Left(val) => val.get(),
             Either::Right(val) => val.get(),
@@ -26,22 +32,16 @@
     }
 }
 
-fn add_generic<A: Add<B>, B>(lhs: A, rhs: B) -> Either<
-    impl Trait<<A as Add<B>>::Output>,
-    impl Trait<<A as Add<B>>::Output>
-> {
-    if true {
-        Either::Left(Holder(lhs + rhs))
-    } else {
-        Either::Right(Holder(lhs + rhs))
-    }
+fn add_generic<A: Add<B>, B>(
+    lhs: A,
+    rhs: B,
+) -> Either<impl Trait<<A as Add<B>>::Output>, impl Trait<<A as Add<B>>::Output>> {
+    if true { Either::Left(Holder(lhs + rhs)) } else { Either::Right(Holder(lhs + rhs)) }
 }
 
 fn add_one(
     value: u32,
 ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
-    //~^ ERROR: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>`
-    //~| ERROR: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>`
     add_generic(value, 1u32)
 }
 
diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr
deleted file mode 100644
index ade85d8..0000000
--- a/src/test/ui/issues/issue-58344.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0277]: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>` is not satisfied
-  --> $DIR/issue-58344.rs:42:13
-   |
-LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as Add>::Output>`
-...
-LL |     add_generic(value, 1u32)
-   |     ------------------------ this returned value is of type `Either<impl Trait<<u32 as Add>::Output>, impl Trait<<u32 as Add>::Output>>`
-   |
-   = note: the return type of a function must have a statically known size
-
-error[E0277]: the trait bound `impl Trait<<u32 as Add>::Output>: Trait<u32>` is not satisfied
-  --> $DIR/issue-58344.rs:42:52
-   |
-LL | ) -> Either<impl Trait<<u32 as Add<u32>>::Output>, impl Trait<<u32 as Add<u32>>::Output>> {
-   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<u32>` is not implemented for `impl Trait<<u32 as Add>::Output>`
-...
-LL |     add_generic(value, 1u32)
-   |     ------------------------ this returned value is of type `Either<impl Trait<<u32 as Add>::Output>, impl Trait<<u32 as Add>::Output>>`
-   |
-   = note: the return type of a function must have a statically known size
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-59508-1.stderr b/src/test/ui/issues/issue-59508-1.stderr
index 5e97339..2a4ccda 100644
--- a/src/test/ui/issues/issue-59508-1.stderr
+++ b/src/test/ui/issues/issue-59508-1.stderr
@@ -12,6 +12,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/issues/issue-60283.rs b/src/test/ui/issues/issue-60283.rs
index 9c2b2dc..c63b154 100644
--- a/src/test/ui/issues/issue-60283.rs
+++ b/src/test/ui/issues/issue-60283.rs
@@ -16,4 +16,5 @@
 fn main() {
     foo((), drop)
     //~^ ERROR type mismatch in function arguments
+    //~| ERROR size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
 }
diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr
index ad679bf..650570b 100644
--- a/src/test/ui/issues/issue-60283.stderr
+++ b/src/test/ui/issues/issue-60283.stderr
@@ -13,6 +13,24 @@
    |             expected signature of `fn(<() as Trait<'a>>::Item) -> _`
    |             found signature of `fn(()) -> _`
 
-error: aborting due to previous error
+error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
+  --> $DIR/issue-60283.rs:17:13
+   |
+LL |     foo((), drop)
+   |             ^^^^ doesn't have a size known at compile-time
+   | 
+  ::: $SRC_DIR/core/src/mem/mod.rs:LL:COL
+   |
+LL | pub fn drop<T>(_x: T) {}
+   |             - required by this bound in `std::mem::drop`
+   |
+   = help: the trait `Sized` is not implemented for `<() as Trait<'_>>::Item`
+help: consider further restricting the associated type
+   |
+LL | fn main() where <() as Trait<'_>>::Item: Sized {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-For more information about this error, try `rustc --explain E0631`.
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0631.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr
index aa43ac9..64cc0ba 100644
--- a/src/test/ui/issues/issue-65673.stderr
+++ b/src/test/ui/issues/issue-65673.stderr
@@ -1,13 +1,11 @@
 error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
-  --> $DIR/issue-65673.rs:9:16
+  --> $DIR/issue-65673.rs:9:5
    |
-LL | trait WithType {
-   |       -------- required by a bound in this
 LL |     type Ctx;
-   |     --------- required by this bound in `WithType`
+   |     --------- required by this bound in `WithType::Ctx`
 ...
 LL |     type Ctx = dyn Alias<T>;
-   |                ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)`
 
diff --git a/src/test/ui/issues/issue-68010-large-zst-consts.rs b/src/test/ui/issues/issue-68010-large-zst-consts.rs
new file mode 100644
index 0000000..4f1bd45
--- /dev/null
+++ b/src/test/ui/issues/issue-68010-large-zst-consts.rs
@@ -0,0 +1,5 @@
+// build-pass
+
+fn main() {
+    println!("{}", [(); std::usize::MAX].len());
+}
diff --git a/src/test/ui/issues/issue-68951.rs b/src/test/ui/issues/issue-68951.rs
new file mode 100644
index 0000000..1c1e92c
--- /dev/null
+++ b/src/test/ui/issues/issue-68951.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+fn main() {
+    let array = [0x42u8; 10];
+    for b in &array {
+        let lo = b & 0xf;
+        let hi = (b >> 4) & 0xf;
+    }
+}
diff --git a/src/test/ui/issues/issue-69532.rs b/src/test/ui/issues/issue-69532.rs
new file mode 100644
index 0000000..81007b1
--- /dev/null
+++ b/src/test/ui/issues/issue-69532.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![feature(const_fn_transmute)]
+
+const fn make_nans() -> (f64, f64, f32, f32) {
+    let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) };
+    let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) };
+
+    let nan1_32 = nan1 as f32;
+    let nan2_32 = nan2 as f32;
+
+    (nan1, nan2, nan1_32, nan2_32)
+}
+
+static NANS: (f64, f64, f32, f32) = make_nans();
+
+fn main() {
+    let (nan1, nan2, nan1_32, nan2_32) = NANS;
+
+    assert!(nan1.is_nan());
+    assert!(nan2.is_nan());
+
+    assert!(nan1_32.is_nan());
+    assert!(nan2_32.is_nan());
+}
diff --git a/src/test/ui/issues/issue-72690.stderr b/src/test/ui/issues/issue-72690.stderr
index feb1316..3443cca 100644
--- a/src/test/ui/issues/issue-72690.stderr
+++ b/src/test/ui/issues/issue-72690.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-72690.rs:7:5
    |
 LL |     String::from("x".as_ref());
-   |     ^^^^^^^^^^^^ cannot infer type for struct `String`
+   |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
    = note: cannot satisfy `String: From<&_>`
    = note: required by `from`
@@ -13,11 +13,13 @@
 LL |     |x| String::from("x".as_ref());
    |      ^ consider giving this closure parameter a type
 
-error[E0283]: type annotations needed
+error[E0283]: type annotations needed for `&T`
   --> $DIR/issue-72690.rs:15:17
    |
 LL |     let _ = "x".as_ref();
-   |                 ^^^^^^ cannot infer type for type `str`
+   |         -       ^^^^^^ cannot infer type for type parameter `T` declared on the trait `AsRef`
+   |         |
+   |         consider giving this pattern the explicit type `&T`, where the type parameter `T` is specified
    |
    = note: cannot satisfy `str: AsRef<_>`
 
@@ -25,7 +27,7 @@
   --> $DIR/issue-72690.rs:19:5
    |
 LL |     String::from("x".as_ref());
-   |     ^^^^^^^^^^^^ cannot infer type for struct `String`
+   |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
    = note: cannot satisfy `String: From<&_>`
    = note: required by `from`
@@ -34,7 +36,7 @@
   --> $DIR/issue-72690.rs:25:5
    |
 LL |     String::from("x".as_ref());
-   |     ^^^^^^^^^^^^ cannot infer type for struct `String`
+   |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
    = note: cannot satisfy `String: From<&_>`
    = note: required by `from`
@@ -43,41 +45,34 @@
   --> $DIR/issue-72690.rs:33:5
    |
 LL |     String::from("x".as_ref());
-   |     ^^^^^^^^^^^^ cannot infer type for struct `String`
+   |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
    = note: cannot satisfy `String: From<&_>`
    = note: required by `from`
 
-error[E0283]: type annotations needed for `String`
+error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:41:5
    |
 LL |     String::from("x".as_ref());
-   |     ^^^^^^^^^^^^ cannot infer type for struct `String`
-LL |     let _ = String::from("x");
-   |         - consider giving this pattern a type
+   |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
    = note: cannot satisfy `String: From<&_>`
    = note: required by `from`
 
-error[E0283]: type annotations needed for `String`
+error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:47:5
    |
-LL |     let _ = String::from("x");
-   |         - consider giving this pattern a type
 LL |     String::from("x".as_ref());
-   |     ^^^^^^^^^^^^ cannot infer type for struct `String`
+   |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
    = note: cannot satisfy `String: From<&_>`
    = note: required by `from`
 
-error[E0283]: type annotations needed for `String`
+error[E0283]: type annotations needed
   --> $DIR/issue-72690.rs:55:5
    |
-LL |     let _ = String::from("x");
-   |         - consider giving this pattern a type
-...
 LL |     String::from("x".as_ref());
-   |     ^^^^^^^^^^^^ cannot infer type for struct `String`
+   |     ^^^^^^^^^^^^ cannot infer type for reference `&_`
    |
    = note: cannot satisfy `String: From<&_>`
    = note: required by `from`
diff --git a/src/test/ui/issues/issue-73427.rs b/src/test/ui/issues/issue-73427.rs
new file mode 100644
index 0000000..3c62782
--- /dev/null
+++ b/src/test/ui/issues/issue-73427.rs
@@ -0,0 +1,44 @@
+enum A {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Struct {},
+    Tuple(),
+    Unit,
+}
+
+enum B {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+}
+
+enum C {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Unit,
+}
+
+enum D {
+    TupleWithFields(()),
+    Unit,
+}
+
+fn main() {
+    // Only variants without fields are suggested (and others mentioned in a note) where an enum
+    // is used rather than a variant.
+
+    A.foo();
+    //~^ ERROR expected value, found enum `A`
+    B.foo();
+    //~^ ERROR expected value, found enum `B`
+    C.foo();
+    //~^ ERROR expected value, found enum `C`
+    D.foo();
+    //~^ ERROR expected value, found enum `D`
+
+    // Only tuple variants are suggested in calls or tuple struct pattern matching.
+
+    let x = A(3);
+    //~^ ERROR expected function, tuple struct or tuple variant, found enum `A`
+    if let A(3) = x { }
+    //~^ ERROR expected tuple struct or tuple variant, found enum `A`
+}
diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr
new file mode 100644
index 0000000..4b5f65b
--- /dev/null
+++ b/src/test/ui/issues/issue-73427.stderr
@@ -0,0 +1,156 @@
+error[E0423]: expected value, found enum `A`
+  --> $DIR/issue-73427.rs:29:5
+   |
+LL |     A.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use one of the following enum variants
+   |
+LL |     (A::Struct {}).foo();
+   |     ^^^^^^^^^^^^^^
+LL |     (A::Tuple()).foo();
+   |     ^^^^^^^^^^^^
+LL |     A::Unit.foo();
+   |     ^^^^^^^
+help: the following enum variants are available
+   |
+LL |     (A::StructWithFields { /* fields */ }).foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (A::TupleWithFields(/* fields */)).foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0423]: expected value, found enum `B`
+  --> $DIR/issue-73427.rs:31:5
+   |
+LL |     B.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:9:1
+   |
+LL | / enum B {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | | }
+   | |_^
+help: the following enum variants are available
+   |
+LL |     (B::StructWithFields { /* fields */ }).foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (B::TupleWithFields(/* fields */)).foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0423]: expected value, found enum `C`
+  --> $DIR/issue-73427.rs:33:5
+   |
+LL |     C.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:14:1
+   |
+LL | / enum C {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use the following enum variant
+   |
+LL |     C::Unit.foo();
+   |     ^^^^^^^
+help: the following enum variants are available
+   |
+LL |     (C::StructWithFields { /* fields */ }).foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     (C::TupleWithFields(/* fields */)).foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0423]: expected value, found enum `D`
+  --> $DIR/issue-73427.rs:35:5
+   |
+LL |     D.foo();
+   |     ^
+   |
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:20:1
+   |
+LL | / enum D {
+LL | |     TupleWithFields(()),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: you might have meant to use the following enum variant
+   |
+LL |     D::Unit.foo();
+   |     ^^^^^^^
+help: the following enum variant is available
+   |
+LL |     (D::TupleWithFields(/* fields */)).foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:40:13
+   |
+LL |     let x = A(3);
+   |             ^
+   |
+   = help: you might have meant to construct one of the enum's non-tuple variants
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: try to construct one of the enum's variants
+   |
+LL |     let x = A::TupleWithFields(3);
+   |             ^^^^^^^^^^^^^^^^^^
+LL |     let x = A::Tuple(3);
+   |             ^^^^^^^^
+
+error[E0532]: expected tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:42:12
+   |
+LL |     if let A(3) = x { }
+   |            ^
+   |
+   = help: you might have meant to match against one of the enum's non-tuple variants
+note: the enum is defined here
+  --> $DIR/issue-73427.rs:1:1
+   |
+LL | / enum A {
+LL | |     StructWithFields { x: () },
+LL | |     TupleWithFields(()),
+LL | |     Struct {},
+LL | |     Tuple(),
+LL | |     Unit,
+LL | | }
+   | |_^
+help: try to match against one of the enum's variants
+   |
+LL |     if let A::TupleWithFields(3) = x { }
+   |            ^^^^^^^^^^^^^^^^^^
+LL |     if let A::Tuple(3) = x { }
+   |            ^^^^^^^^
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0423, E0532.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/issues/issue-7364.rs b/src/test/ui/issues/issue-7364.rs
index 3945289..29a1644 100644
--- a/src/test/ui/issues/issue-7364.rs
+++ b/src/test/ui/issues/issue-7364.rs
@@ -6,6 +6,5 @@
 static boxed: Box<RefCell<isize>> = box RefCell::new(0);
 //~^ ERROR allocations are not allowed in statics
 //~| ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
-//~| ERROR static contains unimplemented expression type
 
 fn main() { }
diff --git a/src/test/ui/issues/issue-7364.stderr b/src/test/ui/issues/issue-7364.stderr
index 90f3bf5..8ceb3be 100644
--- a/src/test/ui/issues/issue-7364.stderr
+++ b/src/test/ui/issues/issue-7364.stderr
@@ -4,14 +4,6 @@
 LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
    |                                     ^^^^^^^^^^^^^^^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/issue-7364.rs:6:41
-   |
-LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
-   |                                         ^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0277]: `RefCell<isize>` cannot be shared between threads safely
   --> $DIR/issue-7364.rs:6:1
    |
@@ -23,7 +15,7 @@
    = note: required because it appears within the type `Box<RefCell<isize>>`
    = note: shared static variables must have a type that implements `Sync`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0010, E0019, E0277.
+Some errors have detailed explanations: E0010, E0277.
 For more information about an error, try `rustc --explain E0010`.
diff --git a/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs b/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs
index 36e9932..44ea9f1 100644
--- a/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs
+++ b/src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs
@@ -1,5 +1,6 @@
 // build-pass
 // ignore-tidy-filelength
+// ignore-compare-mode-chalk
 #![crate_type = "rlib"]
 
 fn banana(v: &str) -> u32 {
diff --git a/src/test/ui/issues/issue-78115.rs b/src/test/ui/issues/issue-78115.rs
new file mode 100644
index 0000000..ac18470
--- /dev/null
+++ b/src/test/ui/issues/issue-78115.rs
@@ -0,0 +1,19 @@
+// Regression test for issue #78115: "ICE: variable should be placed in scope earlier"
+
+// check-pass
+// edition:2018
+
+#[allow(dead_code)]
+struct Foo {
+    a: ()
+}
+
+async fn _bar() {
+    let foo = Foo { a: () };
+    match foo {
+        Foo { a: _a } | Foo { a: _a } if true => {}
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-8460-const.noopt.stderr b/src/test/ui/issues/issue-8460-const.noopt.stderr
index eb8d667..739b546 100644
--- a/src/test/ui/issues/issue-8460-const.noopt.stderr
+++ b/src/test/ui/issues/issue-8460-const.noopt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-8460-const.rs:14:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@
   --> $DIR/issue-8460-const.rs:16:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:18:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:20:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:22:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to divide 1_isize by zero
+   |                                    ^^^^^^^^^^ attempt to divide `1_isize` by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -48,103 +48,103 @@
   --> $DIR/issue-8460-const.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to divide 1_i8 by zero
+   |                                    ^^^^^^^ attempt to divide `1_i8` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i16 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i32 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i64 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to divide 1_i128 by zero
+   |                                    ^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:44:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
+   |                                    ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
+   |                                    ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:56:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
+   |                                    ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/issues/issue-8460-const.opt.stderr b/src/test/ui/issues/issue-8460-const.opt.stderr
index eb8d667..739b546 100644
--- a/src/test/ui/issues/issue-8460-const.opt.stderr
+++ b/src/test/ui/issues/issue-8460-const.opt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-8460-const.rs:14:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@
   --> $DIR/issue-8460-const.rs:16:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:18:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:20:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:22:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to divide 1_isize by zero
+   |                                    ^^^^^^^^^^ attempt to divide `1_isize` by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -48,103 +48,103 @@
   --> $DIR/issue-8460-const.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to divide 1_i8 by zero
+   |                                    ^^^^^^^ attempt to divide `1_i8` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i16 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i32 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i64 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to divide 1_i128 by zero
+   |                                    ^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:44:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
+   |                                    ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
+   |                                    ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:56:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
+   |                                    ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr
index eb8d667..739b546 100644
--- a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr
+++ b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-8460-const.rs:14:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default
 
@@ -10,37 +10,37 @@
   --> $DIR/issue-8460-const.rs:16:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:18:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:20:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:22:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to divide 1_isize by zero
+   |                                    ^^^^^^^^^^ attempt to divide `1_isize` by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -48,103 +48,103 @@
   --> $DIR/issue-8460-const.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to divide 1_i8 by zero
+   |                                    ^^^^^^^ attempt to divide `1_i8` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i16 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i16` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i32 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i32` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to divide 1_i64 by zero
+   |                                    ^^^^^^^^ attempt to divide `1_i64` by zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to divide 1_i128 by zero
+   |                                    ^^^^^^^^^ attempt to divide `1_i128` by zero
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow
+   |                                    ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow
+   |                                    ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:44:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow
+   |                                    ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow
 
 error: this arithmetic operation will overflow
   --> $DIR/issue-8460-const.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
-   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow
+   |                                    ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
-   |                                    ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero
+   |                                    ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
-   |                                    ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero
+   |                                    ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:56:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
-   |                                    ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero
+   |                                    ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero
 
 error: this operation will panic at runtime
   --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
-   |                                    ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero
+   |                                    ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero
 
 error: aborting due to 24 previous errors
 
diff --git a/src/test/ui/iterators/array-of-ranges.stderr b/src/test/ui/iterators/array-of-ranges.stderr
index 6271d81..601983a 100644
--- a/src/test/ui/iterators/array-of-ranges.stderr
+++ b/src/test/ui/iterators/array-of-ranges.stderr
@@ -6,6 +6,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
    = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 1]`
    = note: required by `into_iter`
 
 error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator
@@ -16,6 +17,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[RangeInclusive<{integer}>; 1]`
    = note: required by `into_iter`
 
 error[E0277]: `[RangeFrom<{integer}>; 1]` is not an iterator
@@ -26,6 +28,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[RangeFrom<{integer}>; 1]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[RangeFrom<{integer}>; 1]`
    = note: required by `into_iter`
 
 error[E0277]: `[RangeTo<{integer}>; 1]` is not an iterator
@@ -36,6 +39,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[RangeTo<{integer}>; 1]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[RangeTo<{integer}>; 1]`
    = note: required by `into_iter`
 
 error[E0277]: `[RangeToInclusive<{integer}>; 1]` is not an iterator
@@ -46,6 +50,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[RangeToInclusive<{integer}>; 1]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[RangeToInclusive<{integer}>; 1]`
    = note: required by `into_iter`
 
 error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
@@ -56,6 +61,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
    = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 1]`
    = note: required by `into_iter`
 
 error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator
@@ -66,6 +72,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]`
    = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 1]`
    = note: required by `into_iter`
 
 error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator
@@ -76,6 +83,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[std::ops::Range<{integer}>; 2]`
    = note: required by `into_iter`
 
 error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator
@@ -86,6 +94,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[RangeInclusive<{integer}>; 1]`
    = note: required by `into_iter`
 
 error: aborting due to 9 previous errors
diff --git a/src/test/ui/iterators/array.stderr b/src/test/ui/iterators/array.stderr
index f86c82e..68c6de5 100644
--- a/src/test/ui/iterators/array.stderr
+++ b/src/test/ui/iterators/array.stderr
@@ -6,6 +6,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[{integer}; 2]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[{integer}; 2]`
    = note: required by `into_iter`
 
 error[E0277]: `[{integer}; 2]` is not an iterator
@@ -16,6 +17,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[{integer}; 2]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[{integer}; 2]`
    = note: required by `into_iter`
 
 error[E0277]: `[{float}; 2]` is not an iterator
@@ -26,6 +28,7 @@
    |
    = help: the trait `Iterator` is not implemented for `[{float}; 2]`
    = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
+   = note: required because of the requirements on the impl of `IntoIterator` for `[{float}; 2]`
    = note: required by `into_iter`
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/iterators/integral.stderr b/src/test/ui/iterators/integral.stderr
index c4c4641..e31ee59 100644
--- a/src/test/ui/iterators/integral.stderr
+++ b/src/test/ui/iterators/integral.stderr
@@ -6,6 +6,7 @@
    |
    = help: the trait `Iterator` is not implemented for `{integer}`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `{integer}`
    = note: required by `into_iter`
 
 error[E0277]: `u8` is not an iterator
@@ -16,6 +17,7 @@
    |
    = help: the trait `Iterator` is not implemented for `u8`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `u8`
    = note: required by `into_iter`
 
 error[E0277]: `i8` is not an iterator
@@ -26,6 +28,7 @@
    |
    = help: the trait `Iterator` is not implemented for `i8`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `i8`
    = note: required by `into_iter`
 
 error[E0277]: `u16` is not an iterator
@@ -36,6 +39,7 @@
    |
    = help: the trait `Iterator` is not implemented for `u16`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `u16`
    = note: required by `into_iter`
 
 error[E0277]: `i16` is not an iterator
@@ -46,6 +50,7 @@
    |
    = help: the trait `Iterator` is not implemented for `i16`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `i16`
    = note: required by `into_iter`
 
 error[E0277]: `u32` is not an iterator
@@ -56,6 +61,7 @@
    |
    = help: the trait `Iterator` is not implemented for `u32`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `u32`
    = note: required by `into_iter`
 
 error[E0277]: `i32` is not an iterator
@@ -66,6 +72,7 @@
    |
    = help: the trait `Iterator` is not implemented for `i32`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `i32`
    = note: required by `into_iter`
 
 error[E0277]: `u64` is not an iterator
@@ -76,6 +83,7 @@
    |
    = help: the trait `Iterator` is not implemented for `u64`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `u64`
    = note: required by `into_iter`
 
 error[E0277]: `i64` is not an iterator
@@ -86,6 +94,7 @@
    |
    = help: the trait `Iterator` is not implemented for `i64`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `i64`
    = note: required by `into_iter`
 
 error[E0277]: `usize` is not an iterator
@@ -96,6 +105,7 @@
    |
    = help: the trait `Iterator` is not implemented for `usize`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `usize`
    = note: required by `into_iter`
 
 error[E0277]: `isize` is not an iterator
@@ -106,6 +116,7 @@
    |
    = help: the trait `Iterator` is not implemented for `isize`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+   = note: required because of the requirements on the impl of `IntoIterator` for `isize`
    = note: required by `into_iter`
 
 error[E0277]: `{float}` is not an iterator
@@ -115,6 +126,7 @@
    |              ^^^^ `{float}` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `{float}`
+   = note: required because of the requirements on the impl of `IntoIterator` for `{float}`
    = note: required by `into_iter`
 
 error: aborting due to 12 previous errors
diff --git a/src/test/ui/iterators/iter-zip.rs b/src/test/ui/iterators/iter-zip.rs
deleted file mode 100644
index a76fa24..0000000
--- a/src/test/ui/iterators/iter-zip.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-// run-pass
-// Test that .zip() specialization preserves side effects
-// in sideeffectful iterator adaptors.
-
-use std::cell::Cell;
-
-#[derive(Debug)]
-struct CountClone(Cell<i32>);
-
-fn count_clone() -> CountClone { CountClone(Cell::new(0)) }
-
-impl PartialEq<i32> for CountClone {
-    fn eq(&self, rhs: &i32) -> bool {
-        self.0.get() == *rhs
-    }
-}
-
-impl Clone for CountClone {
-    fn clone(&self) -> Self {
-        let ret = CountClone(self.0.clone());
-        let n = self.0.get();
-        self.0.set(n + 1);
-        ret
-    }
-}
-
-fn test_zip_cloned_sideffectful() {
-    let xs = [count_clone(), count_clone(), count_clone(), count_clone()];
-    let ys = [count_clone(), count_clone()];
-
-    for _ in xs.iter().cloned().zip(ys.iter().cloned()) { }
-
-    assert_eq!(&xs, &[1, 1, 1, 0][..]);
-    assert_eq!(&ys, &[1, 1][..]);
-
-    let xs = [count_clone(), count_clone()];
-    let ys = [count_clone(), count_clone(), count_clone(), count_clone()];
-
-    for _ in xs.iter().cloned().zip(ys.iter().cloned()) { }
-
-    assert_eq!(&xs, &[1, 1][..]);
-    assert_eq!(&ys, &[1, 1, 0, 0][..]);
-}
-
-fn test_zip_map_sideffectful() {
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { }
-
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
-    assert_eq!(&ys, &[1, 1, 1, 1]);
-
-    let mut xs = [0; 4];
-    let mut ys = [0; 6];
-
-    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { }
-
-    assert_eq!(&xs, &[1, 1, 1, 1]);
-    assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
-}
-
-fn test_zip_map_rev_sideffectful() {
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    {
-        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
-        it.next_back();
-    }
-    assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
-    assert_eq!(&ys, &[0, 0, 0, 1]);
-
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    {
-        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
-        (&mut it).take(5).count();
-        it.next_back();
-    }
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
-    assert_eq!(&ys, &[1, 1, 1, 1]);
-}
-
-fn test_zip_nested_sideffectful() {
-    let mut xs = [0; 6];
-    let ys = [0; 4];
-
-    {
-        // test that it has the side effect nested inside enumerate
-        let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
-        it.count();
-    }
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
-}
-
-fn main() {
-    test_zip_cloned_sideffectful();
-    test_zip_map_sideffectful();
-    test_zip_map_rev_sideffectful();
-    test_zip_nested_sideffectful();
-}
diff --git a/src/test/ui/iterators/ranges.stderr b/src/test/ui/iterators/ranges.stderr
index 0324d5f..4678baf 100644
--- a/src/test/ui/iterators/ranges.stderr
+++ b/src/test/ui/iterators/ranges.stderr
@@ -5,6 +5,7 @@
    |              ^^^^ `RangeTo<{integer}>` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `RangeTo<{integer}>`
    = note: required by `into_iter`
 
 error[E0277]: `RangeToInclusive<{integer}>` is not an iterator
@@ -14,6 +15,7 @@
    |              ^^^^^ `RangeToInclusive<{integer}>` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `RangeToInclusive<{integer}>`
    = note: required by `into_iter`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/iterators/string.stderr b/src/test/ui/iterators/string.stderr
index fecdbd1..1653006 100644
--- a/src/test/ui/iterators/string.stderr
+++ b/src/test/ui/iterators/string.stderr
@@ -5,6 +5,7 @@
    |              ^^^^^^^^^^^^^ `String` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `String`
+   = note: required because of the requirements on the impl of `IntoIterator` for `String`
    = note: required by `into_iter`
 
 error[E0277]: `&str` is not an iterator
@@ -14,6 +15,7 @@
    |              ^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
    |
    = help: the trait `Iterator` is not implemented for `&str`
+   = note: required because of the requirements on the impl of `IntoIterator` for `&str`
    = note: required by `into_iter`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
index a6fd44d..64e56f8 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
@@ -12,25 +12,30 @@
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/kindck-inherited-copy-bound.rs:28:19
    |
+LL |     let z = &x as &dyn Foo;
+   |                   ^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/kindck-inherited-copy-bound.rs:10:13
+   |
 LL | trait Foo : Copy {
-   |       ---   ---- ...because it requires `Self: Sized`
+   |       ---   ^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     let z = &x as &dyn Foo;
-   |                   ^^^^^^^^ the trait `Foo` cannot be made into an object
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/kindck-inherited-copy-bound.rs:28:13
    |
+LL |     let z = &x as &dyn Foo;
+   |             ^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/kindck-inherited-copy-bound.rs:10:13
+   |
 LL | trait Foo : Copy {
-   |       ---   ---- ...because it requires `Self: Sized`
+   |       ---   ^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     let z = &x as &dyn Foo;
-   |             ^^ the trait `Foo` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Foo>` for `&Box<{integer}>`
    = note: required by cast to type `&dyn Foo`
 
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
index bc7448a..57f7551 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
@@ -12,14 +12,16 @@
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/kindck-inherited-copy-bound.rs:28:13
    |
+LL |     let z = &x as &dyn Foo;
+   |             ^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/kindck-inherited-copy-bound.rs:10:13
+   |
 LL | trait Foo : Copy {
-   |       ---   ---- ...because it requires `Self: Sized`
+   |       ---   ^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     let z = &x as &dyn Foo;
-   |             ^^ the trait `Foo` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Foo>` for `&Box<i32>`
    = note: required by cast to type `&dyn Foo`
 
diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr
index 45c767f..c7d67a9 100644
--- a/src/test/ui/kindck/kindck-nonsendable-1.stderr
+++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr
@@ -5,12 +5,12 @@
    |                     ---- required by this bound in `bar`
 ...
 LL |     bar(move|| foo(x));
-   |     ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:Rc<usize>]`
+   |     ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`
    |     |
    |     `Rc<usize>` cannot be sent between threads safely
    |
-   = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:Rc<usize>]`, the trait `Send` is not implemented for `Rc<usize>`
-   = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:Rc<usize>]`
+   = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`, the trait `Send` is not implemented for `Rc<usize>`
+   = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
index e43fb6d..c3d597b 100644
--- a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
+++ b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
@@ -3,11 +3,6 @@
    |
 LL | fn foo() -> impl Future<Item=(), Error=Box<dyn Error>> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Future` is not implemented for `std::result::Result<(), _>`
-LL |
-LL |     Ok(())
-   |     ------ this returned value is of type `std::result::Result<(), _>`
-   |
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs
new file mode 100644
index 0000000..8e25227
--- /dev/null
+++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs
@@ -0,0 +1,49 @@
+// This test is checking that you cannot override a `forbid` by adding in other
+// attributes later in the same scope. (We already ensure that you cannot
+// override it in nested scopes).
+
+// If you turn off deduplicate diagnostics (which rustc turns on by default but
+// compiletest turns off when it runs ui tests), then the errors are
+// (unfortunately) repeated here because the checking is done as we read in the
+// errors, and curretly that happens two or three different times, depending on
+// compiler flags.
+//
+// I decided avoiding the redundant output was not worth the time in engineering
+// effort for bug like this, which 1. end users are unlikely to run into in the
+// first place, and 2. they won't see the redundant output anyway.
+
+// compile-flags: -Z deduplicate-diagnostics=yes
+
+fn forbid_first(num: i32) -> i32 {
+    #![forbid(unused)]
+    #![deny(unused)]
+    //~^ ERROR: deny(unused) incompatible with previous forbid in same scope [E0453]
+    #![warn(unused)]
+    //~^ ERROR: warn(unused) incompatible with previous forbid in same scope [E0453]
+    #![allow(unused)]
+    //~^ ERROR: allow(unused) incompatible with previous forbid in same scope [E0453]
+
+    num * num
+}
+
+fn forbid_last(num: i32) -> i32 {
+    #![deny(unused)]
+    #![warn(unused)]
+    #![allow(unused)]
+    #![forbid(unused)]
+
+    num * num
+}
+
+fn forbid_multiple(num: i32) -> i32 {
+    #![forbid(unused)]
+    #![forbid(unused)]
+
+    num * num
+}
+
+fn main() {
+    forbid_first(10);
+    forbid_last(10);
+    forbid_multiple(10);
+}
diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr
new file mode 100644
index 0000000..3951c51
--- /dev/null
+++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr
@@ -0,0 +1,29 @@
+error[E0453]: deny(unused) incompatible with previous forbid in same scope
+  --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:19:13
+   |
+LL |     #![forbid(unused)]
+   |               ------ `forbid` level set here
+LL |     #![deny(unused)]
+   |             ^^^^^^
+
+error[E0453]: warn(unused) incompatible with previous forbid in same scope
+  --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13
+   |
+LL |     #![forbid(unused)]
+   |               ------ `forbid` level set here
+...
+LL |     #![warn(unused)]
+   |             ^^^^^^
+
+error[E0453]: allow(unused) incompatible with previous forbid in same scope
+  --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:23:14
+   |
+LL |     #![forbid(unused)]
+   |               ------ `forbid` level set here
+...
+LL |     #![allow(unused)]
+   |              ^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0453`.
diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs
index 92d29a7..c49a13f 100644
--- a/src/test/ui/lint/lint-const-item-mutation.rs
+++ b/src/test/ui/lint/lint-const-item-mutation.rs
@@ -3,13 +3,32 @@
 struct MyStruct {
     field: bool,
     inner_array: [char; 1],
+    raw_ptr: *mut u8
 }
 impl MyStruct {
     fn use_mut(&mut self) {}
 }
 
+struct Mutable {
+    msg: &'static str,
+}
+impl Drop for Mutable {
+    fn drop(&mut self) {
+        println!("{}", self.msg);
+    }
+}
+
+struct Mutable2 { // this one has drop glue but not a Drop impl
+    msg: &'static str,
+    other: String,
+}
+
 const ARRAY: [u8; 1] = [25];
-const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] };
+const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
+const RAW_PTR: *mut u8 = 1 as *mut u8;
+const MUTABLE: Mutable = Mutable { msg: "" };
+const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
+const VEC: Vec<i32> = Vec::new();
 
 fn main() {
     ARRAY[0] = 5; //~ WARN attempting to modify
@@ -18,4 +37,17 @@
     MY_STRUCT.use_mut(); //~ WARN taking
     &mut MY_STRUCT; //~ WARN taking
     (&mut MY_STRUCT).use_mut(); //~ WARN taking
+
+    // Test that we don't warn when writing through
+    // a raw pointer
+    // This is U.B., but this test is check-pass,
+    // so this never actually executes
+    unsafe {
+        *RAW_PTR = 0;
+        *MY_STRUCT.raw_ptr = 0;
+    }
+
+    MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation
+    MUTABLE2.msg = "wow"; //~ WARN attempting to modify
+    VEC.push(0); //~ WARN taking a mutable reference to a `const` item
 }
diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr
index 2d8f2c4..11b5124 100644
--- a/src/test/ui/lint/lint-const-item-mutation.stderr
+++ b/src/test/ui/lint/lint-const-item-mutation.stderr
@@ -1,5 +1,5 @@
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:15:5
+  --> $DIR/lint-const-item-mutation.rs:34:5
    |
 LL |     ARRAY[0] = 5;
    |     ^^^^^^^^^^^^
@@ -7,39 +7,39 @@
    = note: `#[warn(const_item_mutation)]` on by default
    = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:11:1
+  --> $DIR/lint-const-item-mutation.rs:26:1
    |
 LL | const ARRAY: [u8; 1] = [25];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:16:5
+  --> $DIR/lint-const-item-mutation.rs:35:5
    |
 LL |     MY_STRUCT.field = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:12:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
-LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:17:5
+  --> $DIR/lint-const-item-mutation.rs:36:5
    |
 LL |     MY_STRUCT.inner_array[0] = 'b';
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:12:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
-LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:18:5
+  --> $DIR/lint-const-item-mutation.rs:37:5
    |
 LL |     MY_STRUCT.use_mut();
    |     ^^^^^^^^^^^^^^^^^^^
@@ -47,18 +47,18 @@
    = note: each usage of a `const` item creates a new temporary
    = note: the mutable reference will refer to this temporary, not the original `const` item
 note: mutable reference created due to call to this method
-  --> $DIR/lint-const-item-mutation.rs:8:5
+  --> $DIR/lint-const-item-mutation.rs:9:5
    |
 LL |     fn use_mut(&mut self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:12:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
-LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:19:5
+  --> $DIR/lint-const-item-mutation.rs:38:5
    |
 LL |     &mut MY_STRUCT;
    |     ^^^^^^^^^^^^^^
@@ -66,13 +66,13 @@
    = note: each usage of a `const` item creates a new temporary
    = note: the mutable reference will refer to this temporary, not the original `const` item
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:12:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
-LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:20:5
+  --> $DIR/lint-const-item-mutation.rs:39:5
    |
 LL |     (&mut MY_STRUCT).use_mut();
    |     ^^^^^^^^^^^^^^^^
@@ -80,10 +80,48 @@
    = note: each usage of a `const` item creates a new temporary
    = note: the mutable reference will refer to this temporary, not the original `const` item
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:12:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
-LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'] };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: 6 warnings emitted
+warning: attempting to modify a `const` item
+  --> $DIR/lint-const-item-mutation.rs:51:5
+   |
+LL |     MUTABLE2.msg = "wow";
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
+note: `const` item defined here
+  --> $DIR/lint-const-item-mutation.rs:30:1
+   |
+LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: taking a mutable reference to a `const` item
+  --> $DIR/lint-const-item-mutation.rs:52:5
+   |
+LL |     VEC.push(0);
+   |     ^^^^^^^^^^^
+   |
+   = note: each usage of a `const` item creates a new temporary
+   = note: the mutable reference will refer to this temporary, not the original `const` item
+note: mutable reference created due to call to this method
+  --> $SRC_DIR/alloc/src/vec.rs:LL:COL
+   |
+LL | /     pub fn push(&mut self, value: T) {
+LL | |         // This will panic or abort if we would allocate > isize::MAX bytes
+LL | |         // or if the length increment would overflow for zero-sized types.
+LL | |         if self.len == self.buf.capacity() {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+note: `const` item defined here
+  --> $DIR/lint-const-item-mutation.rs:31:1
+   |
+LL | const VEC: Vec<i32> = Vec::new();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 8 warnings emitted
 
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
index d33b99b..d7fd514 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/lint-exceeding-bitshifts.rs:18:20
    |
 LL |     const N: i32 = T::N << 42;
-   |                    ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
+   |                    ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/lint-exceeding-bitshifts.rs:10:9
@@ -14,139 +14,139 @@
   --> $DIR/lint-exceeding-bitshifts.rs:22:13
    |
 LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left by 42_i32 which would overflow
+   |             ^^^^^^^ attempt to shift left by `42_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:27:15
    |
 LL |       let n = 1u8 << 8;
-   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:29:15
    |
 LL |       let n = 1u16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:31:15
    |
 LL |       let n = 1u32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:33:15
    |
 LL |       let n = 1u64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:35:15
    |
 LL |       let n = 1i8 << 8;
-   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:37:15
    |
 LL |       let n = 1i16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:39:15
    |
 LL |       let n = 1i32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:41:15
    |
 LL |       let n = 1i64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:44:15
    |
 LL |       let n = 1u8 >> 8;
-   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:46:15
    |
 LL |       let n = 1u16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:48:15
    |
 LL |       let n = 1u32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:50:15
    |
 LL |       let n = 1u64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:52:15
    |
 LL |       let n = 1i8 >> 8;
-   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:54:15
    |
 LL |       let n = 1i16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:56:15
    |
 LL |       let n = 1i32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:58:15
    |
 LL |       let n = 1i64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:62:15
    |
 LL |       let n = n << 8;
-   |               ^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:64:15
    |
 LL |       let n = 1u8 << -8;
-   |               ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
+   |               ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:69:15
    |
 LL |       let n = 1u8 << (4+4);
-   |               ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:71:15
    |
 LL |       let n = 1i64 >> [64][0];
-   |               ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_isize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:78:15
    |
 LL |       let n = 1_usize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow
 
 warning: 24 warnings emitted
 
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
index d33b99b..d7fd514 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
@@ -2,7 +2,7 @@
   --> $DIR/lint-exceeding-bitshifts.rs:18:20
    |
 LL |     const N: i32 = T::N << 42;
-   |                    ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
+   |                    ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/lint-exceeding-bitshifts.rs:10:9
@@ -14,139 +14,139 @@
   --> $DIR/lint-exceeding-bitshifts.rs:22:13
    |
 LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left by 42_i32 which would overflow
+   |             ^^^^^^^ attempt to shift left by `42_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:27:15
    |
 LL |       let n = 1u8 << 8;
-   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:29:15
    |
 LL |       let n = 1u16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:31:15
    |
 LL |       let n = 1u32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:33:15
    |
 LL |       let n = 1u64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:35:15
    |
 LL |       let n = 1i8 << 8;
-   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:37:15
    |
 LL |       let n = 1i16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:39:15
    |
 LL |       let n = 1i32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:41:15
    |
 LL |       let n = 1i64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:44:15
    |
 LL |       let n = 1u8 >> 8;
-   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:46:15
    |
 LL |       let n = 1u16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:48:15
    |
 LL |       let n = 1u32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:50:15
    |
 LL |       let n = 1u64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:52:15
    |
 LL |       let n = 1i8 >> 8;
-   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:54:15
    |
 LL |       let n = 1i16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:56:15
    |
 LL |       let n = 1i32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:58:15
    |
 LL |       let n = 1i64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:62:15
    |
 LL |       let n = n << 8;
-   |               ^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:64:15
    |
 LL |       let n = 1u8 << -8;
-   |               ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
+   |               ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:69:15
    |
 LL |       let n = 1u8 << (4+4);
-   |               ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:71:15
    |
 LL |       let n = 1i64 >> [64][0];
-   |               ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_isize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:78:15
    |
 LL |       let n = 1_usize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow
 
 warning: 24 warnings emitted
 
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
index d33b99b..d7fd514 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
@@ -2,7 +2,7 @@
   --> $DIR/lint-exceeding-bitshifts.rs:18:20
    |
 LL |     const N: i32 = T::N << 42;
-   |                    ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow
+   |                    ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/lint-exceeding-bitshifts.rs:10:9
@@ -14,139 +14,139 @@
   --> $DIR/lint-exceeding-bitshifts.rs:22:13
    |
 LL |     let _ = x << 42;
-   |             ^^^^^^^ attempt to shift left by 42_i32 which would overflow
+   |             ^^^^^^^ attempt to shift left by `42_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:27:15
    |
 LL |       let n = 1u8 << 8;
-   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:29:15
    |
 LL |       let n = 1u16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:31:15
    |
 LL |       let n = 1u32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:33:15
    |
 LL |       let n = 1u64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:35:15
    |
 LL |       let n = 1i8 << 8;
-   |               ^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:37:15
    |
 LL |       let n = 1i16 << 16;
-   |               ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:39:15
    |
 LL |       let n = 1i32 << 32;
-   |               ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:41:15
    |
 LL |       let n = 1i64 << 64;
-   |               ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:44:15
    |
 LL |       let n = 1u8 >> 8;
-   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:46:15
    |
 LL |       let n = 1u16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:48:15
    |
 LL |       let n = 1u32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:50:15
    |
 LL |       let n = 1u64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:52:15
    |
 LL |       let n = 1i8 >> 8;
-   |               ^^^^^^^^ attempt to shift right by 8_i32 which would overflow
+   |               ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:54:15
    |
 LL |       let n = 1i16 >> 16;
-   |               ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:56:15
    |
 LL |       let n = 1i32 >> 32;
-   |               ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:58:15
    |
 LL |       let n = 1i64 >> 64;
-   |               ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:62:15
    |
 LL |       let n = n << 8;
-   |               ^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:64:15
    |
 LL |       let n = 1u8 << -8;
-   |               ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow
+   |               ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:69:15
    |
 LL |       let n = 1u8 << (4+4);
-   |               ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow
+   |               ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:71:15
    |
 LL |       let n = 1i64 >> [64][0];
-   |               ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:77:15
    |
 LL |       let n = 1_isize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow
 
 warning: this arithmetic operation will overflow
   --> $DIR/lint-exceeding-bitshifts.rs:78:15
    |
 LL |       let n = 1_usize << BITS;
-   |               ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow
+   |               ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow
 
 warning: 24 warnings emitted
 
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs
index a76ca93..d8774cb 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.rs
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs
@@ -4,7 +4,7 @@
 //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O
 // build-pass
 // ignore-pass (test emits codegen-time warnings and verifies that they are not errors)
-// normalize-stderr-test "shift left by (64|32)_usize which" -> "shift left by %BITS% which"
+// normalize-stderr-test "shift left by `(64|32)_usize`, which" -> "shift left by `%BITS%`, which"
 
 #![crate_type="lib"]
 #![warn(arithmetic_overflow, const_err)]
diff --git a/src/test/ui/lint/lint-unnecessary-parens.fixed b/src/test/ui/lint/lint-unnecessary-parens.fixed
index c9dec39..9c14432 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.fixed
+++ b/src/test/ui/lint/lint-unnecessary-parens.fixed
@@ -60,6 +60,8 @@
     if (v == X { y: true }) {}
     if (X { y: true } == v) {}
     if (X { y: false }.y) {}
+    // this shouldn't warn, because the parens are necessary to disambiguate let chains
+    if let true = (true && false) {}
 
     while (X { y: false }.foo(true)) {}
     while (true | X { y: false }.y) {}
diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs
index 884bb4d..4fd9cab 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.rs
+++ b/src/test/ui/lint/lint-unnecessary-parens.rs
@@ -60,6 +60,8 @@
     if (v == X { y: true }) {}
     if (X { y: true } == v) {}
     if (X { y: false }.y) {}
+    // this shouldn't warn, because the parens are necessary to disambiguate let chains
+    if let true = (true && false) {}
 
     while (X { y: false }.foo(true)) {}
     while (true | X { y: false }.y) {}
diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr
index 1abf47c..9eae7da 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.stderr
+++ b/src/test/ui/lint/lint-unnecessary-parens.stderr
@@ -83,25 +83,25 @@
    |                   ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:71:24
+  --> $DIR/lint-unnecessary-parens.rs:73:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:73:18
+  --> $DIR/lint-unnecessary-parens.rs:75:18
    |
 LL |     let mut _a = (0);
    |                  ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:74:10
+  --> $DIR/lint-unnecessary-parens.rs:76:10
    |
 LL |     _a = (0);
    |          ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:75:11
+  --> $DIR/lint-unnecessary-parens.rs:77:11
    |
 LL |     _a += (1);
    |           ^^^ help: remove these parentheses
diff --git a/src/test/ui/liveness/liveness-asm.rs b/src/test/ui/liveness/liveness-asm.rs
new file mode 100644
index 0000000..b51da0e
--- /dev/null
+++ b/src/test/ui/liveness/liveness-asm.rs
@@ -0,0 +1,44 @@
+// Ensure inout asm! operands are marked as used by the liveness pass
+
+// only-x86_64
+// check-pass
+
+#![feature(asm)]
+#![allow(dead_code)]
+#![warn(unused_assignments)]
+#![warn(unused_variables)]
+
+// Test the single inout case
+unsafe fn f1(mut src: *const u8) {
+    asm!("/*{0}*/", inout(reg) src); //~ WARN value assigned to `src` is never read
+}
+
+unsafe fn f2(mut src: *const u8) -> *const u8 {
+    asm!("/*{0}*/", inout(reg) src);
+    src
+}
+
+// Test the split inout case
+unsafe fn f3(mut src: *const u8) {
+    asm!("/*{0}*/", inout(reg) src => src); //~ WARN value assigned to `src` is never read
+}
+
+unsafe fn f4(mut src: *const u8) -> *const u8 {
+    asm!("/*{0}*/", inout(reg) src => src);
+    src
+}
+
+// Tests the use of field projections
+struct S {
+    field: *mut u8,
+}
+
+unsafe fn f5(src: &mut S) {
+    asm!("/*{0}*/", inout(reg) src.field);
+}
+
+unsafe fn f6(src: &mut S) {
+    asm!("/*{0}*/", inout(reg) src.field => src.field);
+}
+
+fn main() {}
diff --git a/src/test/ui/liveness/liveness-asm.stderr b/src/test/ui/liveness/liveness-asm.stderr
new file mode 100644
index 0000000..f385d7a
--- /dev/null
+++ b/src/test/ui/liveness/liveness-asm.stderr
@@ -0,0 +1,23 @@
+warning: value assigned to `src` is never read
+  --> $DIR/liveness-asm.rs:13:32
+   |
+LL |     asm!("/*{0}*/", inout(reg) src);
+   |                                ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/liveness-asm.rs:8:9
+   |
+LL | #![warn(unused_assignments)]
+   |         ^^^^^^^^^^^^^^^^^^
+   = help: maybe it is overwritten before being read?
+
+warning: value assigned to `src` is never read
+  --> $DIR/liveness-asm.rs:23:39
+   |
+LL |     asm!("/*{0}*/", inout(reg) src => src);
+   |                                       ^^^
+   |
+   = help: maybe it is overwritten before being read?
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/liveness/liveness-consts.rs b/src/test/ui/liveness/liveness-consts.rs
new file mode 100644
index 0000000..8fe2453
--- /dev/null
+++ b/src/test/ui/liveness/liveness-consts.rs
@@ -0,0 +1,63 @@
+// check-pass
+#![warn(unused)]
+#![allow(unreachable_code)]
+
+pub static A: i32 = {
+    let mut i = 0;
+    let mut a = 0; //~ WARN variable `a` is assigned to, but never used
+    while i < 10 {
+        i += 1;
+        a += 1;
+    }
+    i
+};
+
+pub const B: u32 = {
+    let mut b = 1;
+    b += 1; //~ WARN value assigned to `b` is never read
+    b = 42;
+    b
+};
+
+pub enum E {
+    V1 = {
+        let e = 1; //~ WARN unused variable: `e`
+        1
+    },
+    V2 = {
+        let _f = 10;
+        2
+    }
+}
+
+pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8;  { let z = 18; 100 }] {
+    //~^ WARN unused variable: `s`
+    //~| WARN unused variable: `z`
+    x
+}
+
+pub trait T {
+    const T: usize = {
+        let mut t = 10;
+        t = t + t; //~ WARN value assigned to `t` is never read
+        20
+    };
+}
+
+impl T for String {
+    const T: usize = {
+        let w = 10; //~ WARN unused variable: `w`
+        loop {
+            break;
+            let _ = w;
+        }
+        44
+    };
+}
+
+fn main() {
+    let _ = [(); {
+        let z = 42; //~ WARN unused variable: `z`
+        35
+    }];
+}
diff --git a/src/test/ui/liveness/liveness-consts.stderr b/src/test/ui/liveness/liveness-consts.stderr
new file mode 100644
index 0000000..fa8a590
--- /dev/null
+++ b/src/test/ui/liveness/liveness-consts.stderr
@@ -0,0 +1,68 @@
+warning: variable `a` is assigned to, but never used
+  --> $DIR/liveness-consts.rs:7:9
+   |
+LL |     let mut a = 0;
+   |         ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/liveness-consts.rs:2:9
+   |
+LL | #![warn(unused)]
+   |         ^^^^^^
+   = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+   = note: consider using `_a` instead
+
+warning: value assigned to `b` is never read
+  --> $DIR/liveness-consts.rs:17:5
+   |
+LL |     b += 1;
+   |     ^
+   |
+note: the lint level is defined here
+  --> $DIR/liveness-consts.rs:2:9
+   |
+LL | #![warn(unused)]
+   |         ^^^^^^
+   = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]`
+   = help: maybe it is overwritten before being read?
+
+warning: unused variable: `e`
+  --> $DIR/liveness-consts.rs:24:13
+   |
+LL |         let e = 1;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_e`
+
+warning: unused variable: `s`
+  --> $DIR/liveness-consts.rs:33:24
+   |
+LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8;  { let z = 18; 100 }] {
+   |                        ^ help: if this is intentional, prefix it with an underscore: `_s`
+
+warning: unused variable: `z`
+  --> $DIR/liveness-consts.rs:33:55
+   |
+LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8;  { let z = 18; 100 }] {
+   |                                                       ^ help: if this is intentional, prefix it with an underscore: `_z`
+
+warning: unused variable: `z`
+  --> $DIR/liveness-consts.rs:60:13
+   |
+LL |         let z = 42;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_z`
+
+warning: value assigned to `t` is never read
+  --> $DIR/liveness-consts.rs:42:9
+   |
+LL |         t = t + t;
+   |         ^
+   |
+   = help: maybe it is overwritten before being read?
+
+warning: unused variable: `w`
+  --> $DIR/liveness-consts.rs:49:13
+   |
+LL |         let w = 10;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_w`
+
+warning: 8 warnings emitted
+
diff --git a/src/test/ui/liveness/liveness-derive.rs b/src/test/ui/liveness/liveness-derive.rs
new file mode 100644
index 0000000..1921d0d
--- /dev/null
+++ b/src/test/ui/liveness/liveness-derive.rs
@@ -0,0 +1,38 @@
+// Test for interaction between #[automatically_derived] attribute used by
+// built-in derives and lints generated by liveness pass.
+//
+// edition:2018
+// check-pass
+#![warn(unused)]
+
+pub trait T: Sized {
+    const N: usize;
+    fn t(&self) -> Self;
+}
+
+impl T for u32 {
+    const N: usize = {
+        let a = 0; //~ WARN unused variable: `a`
+        4
+    };
+
+    fn t(&self) -> Self {
+        let b = 16; //~ WARN unused variable: `b`
+        0
+    }
+}
+
+#[automatically_derived]
+impl T for i32 {
+    const N: usize = {
+        let c = 0;
+        4
+    };
+
+    fn t(&self) -> Self {
+        let d = 17;
+        0
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/liveness/liveness-derive.stderr b/src/test/ui/liveness/liveness-derive.stderr
new file mode 100644
index 0000000..c03d909
--- /dev/null
+++ b/src/test/ui/liveness/liveness-derive.stderr
@@ -0,0 +1,21 @@
+warning: unused variable: `a`
+  --> $DIR/liveness-derive.rs:15:13
+   |
+LL |         let a = 0;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: the lint level is defined here
+  --> $DIR/liveness-derive.rs:6:9
+   |
+LL | #![warn(unused)]
+   |         ^^^^^^
+   = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: unused variable: `b`
+  --> $DIR/liveness-derive.rs:20:13
+   |
+LL |         let b = 16;
+   |             ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/lto-opt-level-s.rs b/src/test/ui/lto-opt-level-s.rs
new file mode 100644
index 0000000..a7d9d50
--- /dev/null
+++ b/src/test/ui/lto-opt-level-s.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Clinker-plugin-lto -Copt-level=s
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
diff --git a/src/test/ui/lto-opt-level-z.rs b/src/test/ui/lto-opt-level-z.rs
new file mode 100644
index 0000000..bf1f5e2
--- /dev/null
+++ b/src/test/ui/lto-opt-level-z.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Clinker-plugin-lto -Copt-level=z
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
diff --git a/src/test/ui/macros/macro-use-wrong-name.stderr b/src/test/ui/macros/macro-use-wrong-name.stderr
index 74fb519..888fb91 100644
--- a/src/test/ui/macros/macro-use-wrong-name.stderr
+++ b/src/test/ui/macros/macro-use-wrong-name.stderr
@@ -8,6 +8,9 @@
    |
 LL | macro_rules! macro_one { () => ("one") }
    | ---------------------- similarly named macro `macro_one` defined here
+   |
+   = note: consider importing this macro:
+           two_macros::macro_two
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/match/const_non_normal_zst_ref_pattern.rs b/src/test/ui/match/const_non_normal_zst_ref_pattern.rs
new file mode 100644
index 0000000..a114faf
--- /dev/null
+++ b/src/test/ui/match/const_non_normal_zst_ref_pattern.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+const FOO: isize = 10;
+const ZST: &() = unsafe { std::mem::transmute(FOO) };
+fn main() {
+    match &() {
+        ZST => 9,
+    };
+}
diff --git a/src/test/ui/match/match-incompat-type-semi.rs b/src/test/ui/match/match-incompat-type-semi.rs
index 9ab40fa..37f6bea 100644
--- a/src/test/ui/match/match-incompat-type-semi.rs
+++ b/src/test/ui/match/match-incompat-type-semi.rs
@@ -39,4 +39,14 @@
         None => { //~ ERROR incompatible types
         },
     };
+
+    let _ = match Some(42) {
+        Some(x) => "rust-lang.org"
+            .chars()
+            .skip(1)
+            .chain(Some(x as u8 as char))
+            .take(10)
+            .any(char::is_alphanumeric),
+        None => {} //~ ERROR incompatible types
+    };
 }
diff --git a/src/test/ui/match/match-incompat-type-semi.stderr b/src/test/ui/match/match-incompat-type-semi.stderr
index 701f15f..008b1c1 100644
--- a/src/test/ui/match/match-incompat-type-semi.stderr
+++ b/src/test/ui/match/match-incompat-type-semi.stderr
@@ -56,19 +56,33 @@
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-incompat-type-semi.rs:39:17
    |
-LL |        let _ = match Some(42) {
-   |   _____________-
-LL |  |         Some(x) => {
-LL |  |             x
-   |  |             - this is found to be of type `{integer}`
-LL |  |         },
-LL |  |         None => {
-   |  |_________________^
-LL | ||         },
-   | ||_________^ expected integer, found `()`
-LL |  |     };
-   |  |_____- `match` arms have incompatible types
+LL |       let _ = match Some(42) {
+   |               -------------- `match` arms have incompatible types
+LL |           Some(x) => {
+LL |               x
+   |               - this is found to be of type `{integer}`
+LL |           },
+LL |           None => {
+   |  _________________^
+LL | |         },
+   | |_________^ expected integer, found `()`
 
-error: aborting due to 4 previous errors
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/match-incompat-type-semi.rs:50:17
+   |
+LL |       let _ = match Some(42) {
+   |               -------------- `match` arms have incompatible types
+LL |           Some(x) => "rust-lang.org"
+   |  ____________________-
+LL | |             .chars()
+LL | |             .skip(1)
+LL | |             .chain(Some(x as u8 as char))
+LL | |             .take(10)
+LL | |             .any(char::is_alphanumeric),
+   | |_______________________________________- this is found to be of type `bool`
+LL |           None => {}
+   |                   ^^ expected `bool`, found `()`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/match/match-range-fail.rs b/src/test/ui/match/match-range-fail.rs
index c0cdbe3..e53c846 100644
--- a/src/test/ui/match/match-range-fail.rs
+++ b/src/test/ui/match/match-range-fail.rs
@@ -2,17 +2,17 @@
     match "wow" {
         "bar" ..= "foo" => { }
     };
-    //~^^ ERROR only char and numeric types are allowed in range
+    //~^^ ERROR only `char` and numeric types are allowed in range
 
     match "wow" {
         10 ..= "what" => ()
     };
-    //~^^ ERROR only char and numeric types are allowed in range
+    //~^^ ERROR only `char` and numeric types are allowed in range
 
     match "wow" {
         true ..= "what" => {}
     };
-    //~^^ ERROR only char and numeric types are allowed in range
+    //~^^ ERROR only `char` and numeric types are allowed in range
 
     match 5 {
         'c' ..= 100 => { }
diff --git a/src/test/ui/match/match-range-fail.stderr b/src/test/ui/match/match-range-fail.stderr
index 64105dc..938c05a 100644
--- a/src/test/ui/match/match-range-fail.stderr
+++ b/src/test/ui/match/match-range-fail.stderr
@@ -1,4 +1,4 @@
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/match-range-fail.rs:3:9
    |
 LL |         "bar" ..= "foo" => { }
@@ -7,7 +7,7 @@
    |         |         this is of type `&'static str` but it should be `char` or numeric
    |         this is of type `&'static str` but it should be `char` or numeric
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/match-range-fail.rs:8:16
    |
 LL |         10 ..= "what" => ()
@@ -15,7 +15,7 @@
    |         |
    |         this is of type `{integer}`
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/match-range-fail.rs:13:9
    |
 LL |         true ..= "what" => {}
diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index 33e8282..82660a7 100644
--- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -14,7 +14,7 @@
    |            |
    |            expected due to this
    |
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     let y: usize = x.foo().try_into().unwrap();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr
index b0d1bb9..60f9eee 100644
--- a/src/test/ui/methods/method-call-err-msg.stderr
+++ b/src/test/ui/methods/method-call-err-msg.stderr
@@ -1,35 +1,44 @@
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/method-call-err-msg.rs:13:7
    |
-LL |     fn zero(self) -> Foo { self }
-   |     -------------------- defined here
-...
 LL |     x.zero(0)
    |       ^^^^ - supplied 1 argument
    |       |
    |       expected 0 arguments
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:5:8
+   |
+LL |     fn zero(self) -> Foo { self }
+   |        ^^^^ ----
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:14:7
    |
-LL |     fn one(self, _: isize) -> Foo { self }
-   |     ----------------------------- defined here
-...
 LL |      .one()
    |       ^^^- supplied 0 arguments
    |       |
    |       expected 1 argument
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:6:8
+   |
+LL |     fn one(self, _: isize) -> Foo { self }
+   |        ^^^ ----  --------
 
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/method-call-err-msg.rs:15:7
    |
-LL |     fn two(self, _: isize, _: isize) -> Foo { self }
-   |     --------------------------------------- defined here
-...
 LL |      .two(0);
    |       ^^^ - supplied 1 argument
    |       |
    |       expected 2 arguments
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:7:8
+   |
+LL |     fn two(self, _: isize, _: isize) -> Foo { self }
+   |        ^^^ ----  --------  --------
 
 error[E0599]: no method named `take` found for struct `Foo` in the current scope
   --> $DIR/method-call-err-msg.rs:19:7
@@ -53,13 +62,16 @@
 error[E0061]: this function takes 3 arguments but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:21:7
    |
-LL |     fn three<T>(self, _: T, _: T, _: T) -> Foo { self }
-   |     ------------------------------------------ defined here
-...
 LL |     y.three::<usize>();
    |       ^^^^^--------- supplied 0 arguments
    |       |
    |       expected 3 arguments
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:8:8
+   |
+LL |     fn three<T>(self, _: T, _: T, _: T) -> Foo { self }
+   |        ^^^^^    ----  ----  ----  ----
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/mir/auxiliary/issue_76375_aux.rs b/src/test/ui/mir/auxiliary/issue_76375_aux.rs
new file mode 100644
index 0000000..f8b318d
--- /dev/null
+++ b/src/test/ui/mir/auxiliary/issue_76375_aux.rs
@@ -0,0 +1,14 @@
+// edition:2018
+// compile-flags: -Z mir-opt-level=2 -Z unsound-mir-opts
+
+#[inline(always)]
+pub fn f(s: bool) -> String {
+    let a = "Hello world!".to_string();
+    let b = a;
+    let c = b;
+    if s {
+        c
+    } else {
+        String::new()
+    }
+}
diff --git a/src/test/ui/mir/issue-68841.rs b/src/test/ui/mir/issue-68841.rs
new file mode 100644
index 0000000..14884a9
--- /dev/null
+++ b/src/test/ui/mir/issue-68841.rs
@@ -0,0 +1,15 @@
+// compile-flags: -Z mir-opt-level=2
+// edition:2018
+// build-pass
+
+#![feature(async_closure)]
+
+use std::future::Future;
+
+fn async_closure() -> impl Future<Output = u8> {
+    (async move || -> u8 { 42 })()
+}
+
+fn main() {
+    let _fut = async_closure();
+}
diff --git a/src/test/ui/mir/issue-75053.rs b/src/test/ui/mir/issue-75053.rs
new file mode 100644
index 0000000..6e7211c
--- /dev/null
+++ b/src/test/ui/mir/issue-75053.rs
@@ -0,0 +1,48 @@
+// compile-flags: -Z mir-opt-level=2
+// build-pass
+
+#![feature(type_alias_impl_trait)]
+
+use std::marker::PhantomData;
+
+trait MyIndex<T> {
+    type O;
+    fn my_index(self) -> Self::O;
+}
+trait MyFrom<T>: Sized {
+    type Error;
+    fn my_from(value: T) -> Result<Self, Self::Error>;
+}
+
+trait F {}
+impl F for () {}
+type DummyT<T> = impl F;
+fn _dummy_t<T>() -> DummyT<T> {}
+
+struct Phantom1<T>(PhantomData<T>);
+struct Phantom2<T>(PhantomData<T>);
+struct Scope<T>(Phantom2<DummyT<T>>);
+
+impl<T> Scope<T> {
+    fn new() -> Self {
+        unimplemented!()
+    }
+}
+
+impl<T> MyFrom<Phantom2<T>> for Phantom1<T> {
+    type Error = ();
+    fn my_from(_: Phantom2<T>) -> Result<Self, Self::Error> {
+        unimplemented!()
+    }
+}
+
+impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<Phantom1<T>> for Scope<U> {
+    type O = T;
+    fn my_index(self) -> Self::O {
+        MyFrom::my_from(self.0).ok().unwrap()
+    }
+}
+
+fn main() {
+    let _pos: Phantom1<DummyT<()>> = Scope::new().my_index();
+}
diff --git a/src/test/ui/mir/issue-76375.rs b/src/test/ui/mir/issue-76375.rs
new file mode 100644
index 0000000..ef459f6
--- /dev/null
+++ b/src/test/ui/mir/issue-76375.rs
@@ -0,0 +1,15 @@
+// edition:2018
+// build-pass
+// compile-flags: -Z mir-opt-level=2 -L.
+// aux-build:issue_76375_aux.rs
+
+#![crate_type = "lib"]
+
+extern crate issue_76375_aux;
+
+pub async fn g() {
+    issue_76375_aux::f(true);
+    h().await;
+}
+
+pub async fn h() {}
diff --git a/src/test/ui/mir/issue-76740-copy-propagation.rs b/src/test/ui/mir/issue-76740-copy-propagation.rs
index e328394..90999a3 100644
--- a/src/test/ui/mir/issue-76740-copy-propagation.rs
+++ b/src/test/ui/mir/issue-76740-copy-propagation.rs
@@ -1,5 +1,5 @@
 // Regression test for issue #76740.
-// run-fail FIXME: change to run-pass once #76899 lands
+// run-pass
 // compile-flags: -Zmir-opt-level=3
 
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/mir/issue-77359-simplify-arm-identity.rs b/src/test/ui/mir/issue-77359-simplify-arm-identity.rs
new file mode 100644
index 0000000..e58ba50
--- /dev/null
+++ b/src/test/ui/mir/issue-77359-simplify-arm-identity.rs
@@ -0,0 +1,35 @@
+// run-pass
+
+#![allow(dead_code)]
+
+#[derive(Debug)]
+enum MyEnum {
+    Variant1(Vec<u8>),
+    Variant2,
+    Variant3,
+    Variant4,
+}
+
+fn f(arg1: &bool, arg2: &bool, arg3: bool) -> MyStruct {
+    if *arg1 {
+        println!("{:?}", f(&arg2, arg2, arg3));
+        MyStruct(None)
+    } else {
+        match if arg3 { Some(MyEnum::Variant3) } else { None } {
+            Some(t) => {
+                let ah = t;
+                return MyStruct(Some(ah));
+            }
+            _ => MyStruct(None)
+        }
+    }
+}
+
+#[derive(Debug)]
+struct MyStruct(Option<MyEnum>);
+
+fn main() {
+    let arg1 = true;
+    let arg2 = false;
+    f(&arg1, &arg2, true);
+}
diff --git a/src/test/ui/mir/issue-77911.rs b/src/test/ui/mir/issue-77911.rs
new file mode 100644
index 0000000..b24faa6
--- /dev/null
+++ b/src/test/ui/mir/issue-77911.rs
@@ -0,0 +1,16 @@
+// compile-flags: -Z mir-opt-level=2
+// ignore-cloudabi no std::fs
+// build-pass
+
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+
+fn file_lines() -> impl Iterator<Item = String> {
+    BufReader::new(File::open("").unwrap())
+        .lines()
+        .map(Result::unwrap)
+}
+
+fn main() {
+    for _ in file_lines() {}
+}
diff --git a/src/test/ui/mir/mir-inlining/ice-issue-68347.rs b/src/test/ui/mir/mir-inlining/ice-issue-68347.rs
new file mode 100644
index 0000000..88b80bc
--- /dev/null
+++ b/src/test/ui/mir/mir-inlining/ice-issue-68347.rs
@@ -0,0 +1,28 @@
+// run-pass
+// compile-flags:-Zmir-opt-level=2
+pub fn main() {
+    let _x: fn() = handle_debug_column;
+}
+
+fn handle_debug_column() {
+    let sampler = sample_columns();
+
+    let foo = || {
+        sampler.get(17);
+    };
+    foo();
+}
+
+fn sample_columns() -> impl Sampler {
+    ColumnGen {}
+}
+
+struct ColumnGen {}
+
+trait Sampler {
+    fn get(&self, index: i32);
+}
+
+impl Sampler for ColumnGen {
+    fn get(&self, _index: i32) {}
+}
diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs b/src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs
new file mode 100644
index 0000000..4d083bf
--- /dev/null
+++ b/src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs
@@ -0,0 +1,17 @@
+// run-pass
+// compile-flags:-Zmir-opt-level=2
+
+// Previously ICEd because we did not normalize during inlining,
+// see https://github.com/rust-lang/rust/pull/77306 for more discussion.
+
+pub fn write() {
+    create()()
+}
+
+pub fn create() -> impl FnOnce() {
+   || ()
+}
+
+fn main() {
+    write();
+}
diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs b/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs
new file mode 100644
index 0000000..a346d45
--- /dev/null
+++ b/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs
@@ -0,0 +1,32 @@
+// run-pass
+// compile-flags:-Zmir-opt-level=2
+
+struct Cursor {}
+struct TokenTree {}
+
+impl Iterator for Cursor {
+    type Item = TokenTree;
+
+    fn next(&mut self) -> Option<TokenTree> {
+        None
+    }
+}
+
+fn tokenstream_probably_equal_for_proc_macro() {
+    fn break_tokens(_tree: TokenTree) -> impl Iterator<Item = TokenTree> {
+        let token_trees: Vec<TokenTree> = vec![];
+        token_trees.into_iter()
+    }
+
+    let c1 = Cursor {};
+    let c2 = Cursor {};
+
+    let mut t1 = c1.flat_map(break_tokens);
+    let mut t2 = c2.flat_map(break_tokens);
+
+    for (_t1, _t2) in t1.by_ref().zip(t2.by_ref()) {}
+}
+
+fn main() {
+    tokenstream_probably_equal_for_proc_macro();
+}
diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77564.rs b/src/test/ui/mir/mir-inlining/ice-issue-77564.rs
new file mode 100644
index 0000000..262402d
--- /dev/null
+++ b/src/test/ui/mir/mir-inlining/ice-issue-77564.rs
@@ -0,0 +1,38 @@
+// run-pass
+// compile-flags:-Zmir-opt-level=2
+
+use std::mem::MaybeUninit;
+const N: usize = 2;
+
+trait CollectArray<A>: Iterator<Item = A> {
+    fn inner_array(&mut self) -> [A; N];
+    fn collect_array(&mut self) -> [A; N] {
+        let result = self.inner_array();
+        assert!(self.next().is_none());
+        result
+    }
+}
+
+impl<A, I: ?Sized> CollectArray<A> for I
+where
+    I: Iterator<Item = A>,
+{
+    fn inner_array(&mut self) -> [A; N] {
+        let mut result: [MaybeUninit<A>; N] = unsafe { MaybeUninit::uninit().assume_init() };
+        for (dest, item) in result.iter_mut().zip(self) {
+            *dest = MaybeUninit::new(item);
+        }
+        let temp_ptr: *const [MaybeUninit<A>; N] = &result;
+        unsafe { std::ptr::read(temp_ptr as *const [A; N]) }
+    }
+}
+
+fn main() {
+    assert_eq!(
+        [[1, 2], [3, 4]]
+            .iter()
+            .map(|row| row.iter().collect_array())
+            .collect_array(),
+        [[&1, &2], [&3, &4]]
+    );
+}
diff --git a/src/test/ui/mir/mir_detects_invalid_ops.stderr b/src/test/ui/mir/mir_detects_invalid_ops.stderr
index b4f74a5..0fe56f4 100644
--- a/src/test/ui/mir/mir_detects_invalid_ops.stderr
+++ b/src/test/ui/mir/mir_detects_invalid_ops.stderr
@@ -2,7 +2,7 @@
   --> $DIR/mir_detects_invalid_ops.rs:11:14
    |
 LL |     let _z = 1 / y;
-   |              ^^^^^ attempt to divide 1_i32 by zero
+   |              ^^^^^ attempt to divide `1_i32` by zero
    |
    = note: `#[deny(unconditional_panic)]` on by default
 
@@ -10,7 +10,7 @@
   --> $DIR/mir_detects_invalid_ops.rs:16:14
    |
 LL |     let _z = 1 % y;
-   |              ^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero
+   |              ^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mir/simplify-branch-same.rs b/src/test/ui/mir/simplify-branch-same.rs
new file mode 100644
index 0000000..d631c33
--- /dev/null
+++ b/src/test/ui/mir/simplify-branch-same.rs
@@ -0,0 +1,21 @@
+// Regression test for SimplifyBranchSame miscompilation.
+// run-pass
+
+macro_rules! m {
+    ($a:expr, $b:expr, $c:block) => {
+        match $a {
+            Lto::Fat | Lto::Thin => { $b; (); $c }
+            Lto::No => { $b; () }
+        }
+    }
+}
+
+pub enum Lto { No, Thin, Fat }
+
+fn f(mut cookie: u32, lto: Lto) -> u32 {
+    let mut _a = false;
+    m!(lto, _a = true, {cookie = 0});
+    cookie
+}
+
+fn main() { assert_eq!(f(42, Lto::Thin), 0) }
diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs
index 12d4826..4be7420 100644
--- a/src/test/ui/mismatched_types/binops.rs
+++ b/src/test/ui/mismatched_types/binops.rs
@@ -1,7 +1,7 @@
 fn main() {
     1 + Some(1); //~ ERROR cannot add `Option<{integer}>` to `{integer}`
     2 as usize - Some(1); //~ ERROR cannot subtract `Option<{integer}>` from `usize`
-    3 * (); //~ ERROR cannot multiply `()` to `{integer}`
+    3 * (); //~ ERROR cannot multiply `{integer}` by `()`
     4 / ""; //~ ERROR cannot divide `{integer}` by `&str`
     5 < String::new(); //~ ERROR can't compare `{integer}` with `String`
     6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>`
diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr
index 227c788..f2bfb12 100644
--- a/src/test/ui/mismatched_types/binops.stderr
+++ b/src/test/ui/mismatched_types/binops.stderr
@@ -14,7 +14,7 @@
    |
    = help: the trait `Sub<Option<{integer}>>` is not implemented for `usize`
 
-error[E0277]: cannot multiply `()` to `{integer}`
+error[E0277]: cannot multiply `{integer}` by `()`
   --> $DIR/binops.rs:4:7
    |
 LL |     3 * ();
diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr
index d39b0a3..e608cd9 100644
--- a/src/test/ui/mismatched_types/issue-26480.stderr
+++ b/src/test/ui/mismatched_types/issue-26480.stderr
@@ -8,7 +8,7 @@
    |     -------------- in this macro invocation
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
    |
 LL |                   ($arr.len() * size_of($arr[0])).try_into().unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index 63c04bc..0b1fcf5 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -1,3 +1,11 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/issue-36053-2.rs:7:32
+   |
+LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
+   |                                |
+   |                                expected signature of `for<'r> fn(&'r &str) -> _`
+
 error[E0599]: no method named `count` found for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope
   --> $DIR/issue-36053-2.rs:7:55
    |
@@ -20,14 +28,6 @@
            `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
            which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/issue-36053-2.rs:7:32
-   |
-LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
-   |                                |
-   |                                expected signature of `for<'r> fn(&'r &str) -> _`
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0599, E0631.
diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr
index c2bce30..5d2ce93 100644
--- a/src/test/ui/mismatched_types/issue-38371.stderr
+++ b/src/test/ui/mismatched_types/issue-38371.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-38371.rs:4:8
    |
 LL | fn foo(&foo: Foo) {
-   |        ^^^^------
+   |        ^^^^-----
    |        |     |
    |        |     expected due to this
    |        expected struct `Foo`, found reference
diff --git a/src/test/ui/missing/missing-alloc_error_handler.stderr b/src/test/ui/missing/missing-alloc_error_handler.stderr
index 5489b2c..511d078 100644
--- a/src/test/ui/missing/missing-alloc_error_handler.stderr
+++ b/src/test/ui/missing/missing-alloc_error_handler.stderr
@@ -1,4 +1,6 @@
-error: `#[alloc_error_handler]` function required, but not found
+error: `#[alloc_error_handler]` function required, but not found.
+
+note: Use `#![feature(default_alloc_error_handler)]` for a default error handler.
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/missing/missing-macro-use.stderr b/src/test/ui/missing/missing-macro-use.stderr
index 711e249..ced0622 100644
--- a/src/test/ui/missing/missing-macro-use.stderr
+++ b/src/test/ui/missing/missing-macro-use.stderr
@@ -3,6 +3,9 @@
    |
 LL |     macro_two!();
    |     ^^^^^^^^^
+   |
+   = note: consider importing this macro:
+           two_macros::macro_two
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mod/mod_file_aux.rs b/src/test/ui/modules_and_files_visibility/mod_file_aux.rs
similarity index 100%
rename from src/test/ui/mod/mod_file_aux.rs
rename to src/test/ui/modules_and_files_visibility/mod_file_aux.rs
diff --git a/src/test/ui/mod/mod_file_correct_spans.rs b/src/test/ui/modules_and_files_visibility/mod_file_correct_spans.rs
similarity index 100%
rename from src/test/ui/mod/mod_file_correct_spans.rs
rename to src/test/ui/modules_and_files_visibility/mod_file_correct_spans.rs
diff --git a/src/test/ui/mod/mod_file_correct_spans.stderr b/src/test/ui/modules_and_files_visibility/mod_file_correct_spans.stderr
similarity index 100%
rename from src/test/ui/mod/mod_file_correct_spans.stderr
rename to src/test/ui/modules_and_files_visibility/mod_file_correct_spans.stderr
diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/modules_and_files_visibility/mod_file_disambig.rs
similarity index 100%
rename from src/test/ui/mod/mod_file_disambig.rs
rename to src/test/ui/modules_and_files_visibility/mod_file_disambig.rs
diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr
similarity index 100%
rename from src/test/ui/mod/mod_file_disambig.stderr
rename to src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr
diff --git a/src/test/ui/mod/mod_file_disambig_aux.rs b/src/test/ui/modules_and_files_visibility/mod_file_disambig_aux.rs
similarity index 100%
rename from src/test/ui/mod/mod_file_disambig_aux.rs
rename to src/test/ui/modules_and_files_visibility/mod_file_disambig_aux.rs
diff --git a/src/test/ui/mod/mod_file_disambig_aux/mod.rs b/src/test/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs
similarity index 100%
rename from src/test/ui/mod/mod_file_disambig_aux/mod.rs
rename to src/test/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs
diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
index c652faa..670f768 100644
--- a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
+++ b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr
@@ -3,11 +3,6 @@
    |
 LL | fn should_ret_unit() -> impl T {
    |                         ^^^^^^ the trait `T` is not implemented for `()`
-LL |
-LL |     panic!()
-   |     -------- this returned value is of type `!`
-   |
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr
index c54cbe9..16d93c1 100644
--- a/src/test/ui/never_type/issue-51506.stderr
+++ b/src/test/ui/never_type/issue-51506.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-51506.rs:13:5
    |
 LL |     type Out: Iterator<Item = u32>;
-   |     ------------------------------- required by `Trait::Out`
+   |               -------------------- required by this bound in `Trait::Out`
 ...
 LL |     default type Out = !;
    |     ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
index d3964a7..44dcd19 100644
--- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
@@ -32,5 +32,4 @@
     let _x = <fn(&())>::make_f();
     //~^ higher-ranked subtype error
     //~| higher-ranked subtype error
-    //~| higher-ranked subtype error
 }
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
index 70fb877..190b520 100644
--- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
@@ -10,11 +10,5 @@
 LL |     let _x = <fn(&())>::make_f();
    |              ^^^^^^^^^^^^^^^^^^^
 
-error: higher-ranked subtype error
-  --> $DIR/impl-fn-ignore-binder-via-bottom.rs:32:14
-   |
-LL |     let _x = <fn(&())>::make_f();
-   |              ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/ty-outlives/issue-53789-2.rs b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
index 7dcdd58..d15e402 100644
--- a/src/test/ui/nll/ty-outlives/issue-53789-2.rs
+++ b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
@@ -1,6 +1,7 @@
 // Regression test for #53789.
 //
 // check-pass
+// ignore-compare-mode-chalk
 
 use std::collections::BTreeMap;
 use std::ops::Range;
diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr
index 6bd4537..ef7fb4a 100644
--- a/src/test/ui/no-send-res-ports.stderr
+++ b/src/test/ui/no-send-res-ports.stderr
@@ -9,17 +9,17 @@
 LL | |         let y = x;
 LL | |         println!("{:?}", y);
 LL | |     });
-   | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:Foo]`
+   | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`
    | 
   ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
 LL |       F: Send + 'static,
    |          ---- required by this bound in `spawn`
    |
-   = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:Foo]`, the trait `Send` is not implemented for `Rc<()>`
+   = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`, the trait `Send` is not implemented for `Rc<()>`
    = note: required because it appears within the type `Port<()>`
    = note: required because it appears within the type `Foo`
-   = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:Foo]`
+   = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr
index f54a69e..a62c21f 100644
--- a/src/test/ui/not-clone-closure.stderr
+++ b/src/test/ui/not-clone-closure.stderr
@@ -1,16 +1,16 @@
-error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
+error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`
   --> $DIR/not-clone-closure.rs:11:23
    |
 LL |       let hello = move || {
    |  _________________-
 LL | |         println!("Hello {}", a.0);
 LL | |     };
-   | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
+   | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`
 LL | 
 LL |       let hello = hello.clone();
-   |                         ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `Clone` is not implemented for `S`
+   |                         ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`, the trait `Clone` is not implemented for `S`
    |
-   = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`
+   = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/not-enough-arguments.rs b/src/test/ui/not-enough-arguments.rs
index 631bb1d..4247625 100644
--- a/src/test/ui/not-enough-arguments.rs
+++ b/src/test/ui/not-enough-arguments.rs
@@ -6,7 +6,26 @@
   panic!();
 }
 
+// Check that all arguments are shown in the error message, even if they're across multiple lines.
+fn bar(
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+) {
+    println!("{}", a);
+    println!("{}", b);
+    println!("{}", c);
+    println!("{}", d);
+    println!("{}", e);
+    println!("{}", f);
+}
+
 fn main() {
   foo(1, 2, 3);
   //~^ ERROR this function takes 4 arguments but 3
+  bar(1, 2, 3);
+  //~^ ERROR this function takes 6 arguments but 3
 }
diff --git a/src/test/ui/not-enough-arguments.stderr b/src/test/ui/not-enough-arguments.stderr
index f2b57f7..df95783 100644
--- a/src/test/ui/not-enough-arguments.stderr
+++ b/src/test/ui/not-enough-arguments.stderr
@@ -1,14 +1,43 @@
 error[E0061]: this function takes 4 arguments but 3 arguments were supplied
-  --> $DIR/not-enough-arguments.rs:10:3
+  --> $DIR/not-enough-arguments.rs:27:3
    |
-LL | fn foo(a: isize, b: isize, c: isize, d:isize) {
-   | --------------------------------------------- defined here
-...
 LL |   foo(1, 2, 3);
    |   ^^^ -  -  - supplied 3 arguments
    |   |
    |   expected 4 arguments
+   |
+note: function defined here
+  --> $DIR/not-enough-arguments.rs:5:4
+   |
+LL | fn foo(a: isize, b: isize, c: isize, d:isize) {
+   |    ^^^ --------  --------  --------  -------
 
-error: aborting due to previous error
+error[E0061]: this function takes 6 arguments but 3 arguments were supplied
+  --> $DIR/not-enough-arguments.rs:29:3
+   |
+LL |   bar(1, 2, 3);
+   |   ^^^ -  -  - supplied 3 arguments
+   |   |
+   |   expected 6 arguments
+   |
+note: function defined here
+  --> $DIR/not-enough-arguments.rs:10:4
+   |
+LL | fn bar(
+   |    ^^^
+LL |     a: i32,
+   |     ------
+LL |     b: i32,
+   |     ------
+LL |     c: i32,
+   |     ------
+LL |     d: i32,
+   |     ------
+LL |     e: i32,
+   |     ------
+LL |     f: i32,
+   |     ------
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr
index 995afee..1d02993 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-lsh-1.rs:7:14
    |
 LL |     let _x = 1_i32 << 32;
-   |              ^^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow
+   |              ^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-1.rs:4:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr
index e6f6b1c..8598792 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-lsh-2.rs:7:14
    |
 LL |     let _x = 1 << -1;
-   |              ^^^^^^^ attempt to shift left by -1_i32 which would overflow
+   |              ^^^^^^^ attempt to shift left by `-1_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-2.rs:4:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr
index e57b892..9c6f806 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-lsh-3.rs:7:14
    |
 LL |     let _x = 1_u64 << 64;
-   |              ^^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow
+   |              ^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-3.rs:4:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr
index f20b41c..08081a0 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-lsh-4.rs:11:13
    |
 LL |     let x = 1_i8 << 17;
-   |             ^^^^^^^^^^ attempt to shift left by 17_i32 which would overflow
+   |             ^^^^^^^^^^ attempt to shift left by `17_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-lsh-4.rs:7:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr
index 18861a1..4d726fa 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-rsh-1.rs:7:14
    |
 LL |     let _x = -1_i32 >> 32;
-   |              ^^^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow
+   |              ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-1.rs:4:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr
index a2fb2b9..9a8349d 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-rsh-2.rs:7:14
    |
 LL |     let _x = -1_i32 >> -1;
-   |              ^^^^^^^^^^^^ attempt to shift right by -1_i32 which would overflow
+   |              ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-2.rs:4:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr
index 24588b4..f48b7ff 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-rsh-3.rs:7:14
    |
 LL |     let _x = -1_i64 >> 64;
-   |              ^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |              ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-3.rs:4:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr
index 3f59653..4816a38 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-rsh-4.rs:11:13
    |
 LL |     let x = 2_i8 >> 17;
-   |             ^^^^^^^^^^ attempt to shift right by 17_i32 which would overflow
+   |             ^^^^^^^^^^ attempt to shift right by `17_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-4.rs:7:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr
index 8b0daf1..cd36f54 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-rsh-5.rs:7:14
    |
 LL |     let _n = 1i64 >> [64][0];
-   |              ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |              ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-5.rs:4:9
diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr
index 53a1445..bec8b17 100644
--- a/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr
+++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr
@@ -2,7 +2,7 @@
   --> $DIR/overflowing-rsh-6.rs:7:14
    |
 LL |     let _n = 1i64 >> [64][0];
-   |              ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow
+   |              ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow
    |
 note: the lint level is defined here
   --> $DIR/overflowing-rsh-6.rs:4:9
diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr
index d7f18e1..5a275d5 100644
--- a/src/test/ui/numeric/const-scope.stderr
+++ b/src/test/ui/numeric/const-scope.stderr
@@ -57,7 +57,7 @@
    |            |
    |            expected due to this
    |
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     let d: i8 = c.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr
index dba6c72..79b38b0 100644
--- a/src/test/ui/numeric/len.stderr
+++ b/src/test/ui/numeric/len.stderr
@@ -4,7 +4,7 @@
 LL |     test(array.len());
    |          ^^^^^^^^^^^ expected `u32`, found `usize`
    |
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     test(array.len().try_into().unwrap());
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr
index 3f90006..858990f 100644
--- a/src/test/ui/numeric/numeric-cast-2.stderr
+++ b/src/test/ui/numeric/numeric-cast-2.stderr
@@ -6,7 +6,7 @@
    |            |
    |            expected due to this
    |
-help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     let x: u16 = foo().try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -18,7 +18,7 @@
    |            ---   ^^^^^
    |            |     |
    |            |     expected `i64`, found `u16`
-   |            |     help: you can convert an `u16` to `i64`: `(x + x).into()`
+   |            |     help: you can convert a `u16` to an `i64`: `(x + x).into()`
    |            expected due to this
 
 error[E0308]: mismatched types
@@ -28,7 +28,7 @@
    |            ---   ^^^^^
    |            |     |
    |            |     expected `i32`, found `u16`
-   |            |     help: you can convert an `u16` to `i32`: `(x + x).into()`
+   |            |     help: you can convert a `u16` to an `i32`: `(x + x).into()`
    |            expected due to this
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/numeric/numeric-cast-binop.stderr b/src/test/ui/numeric/numeric-cast-binop.stderr
index 47be817..cb051aa 100644
--- a/src/test/ui/numeric/numeric-cast-binop.stderr
+++ b/src/test/ui/numeric/numeric-cast-binop.stderr
@@ -60,7 +60,7 @@
    |                 ^^^^
    |                 |
    |                 expected `u16`, found `u8`
-   |                 help: you can convert an `u8` to `u16`: `x_u8.into()`
+   |                 help: you can convert a `u8` to a `u16`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:36:17
@@ -113,7 +113,7 @@
    |                 ^^^^
    |                 |
    |                 expected `u32`, found `u8`
-   |                 help: you can convert an `u8` to `u32`: `x_u8.into()`
+   |                 help: you can convert a `u8` to a `u32`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:47:17
@@ -122,7 +122,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `u32`, found `u16`
-   |                 help: you can convert an `u16` to `u32`: `x_u16.into()`
+   |                 help: you can convert a `u16` to a `u32`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:49:17
@@ -152,7 +152,7 @@
 LL |         x_u32 > x_usize;
    |                 ^^^^^^^ expected `u32`, found `usize`
    |
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
    |
 LL |         x_u32 > x_usize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -164,7 +164,7 @@
    |                 ^^^^
    |                 |
    |                 expected `u64`, found `u8`
-   |                 help: you can convert an `u8` to `u64`: `x_u8.into()`
+   |                 help: you can convert a `u8` to a `u64`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:58:17
@@ -173,7 +173,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `u64`, found `u16`
-   |                 help: you can convert an `u16` to `u64`: `x_u16.into()`
+   |                 help: you can convert a `u16` to a `u64`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:60:17
@@ -182,7 +182,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `u64`, found `u32`
-   |                 help: you can convert an `u32` to `u64`: `x_u32.into()`
+   |                 help: you can convert a `u32` to a `u64`: `x_u32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:62:17
@@ -201,7 +201,7 @@
 LL |         x_u64 > x_usize;
    |                 ^^^^^^^ expected `u64`, found `usize`
    |
-help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
    |
 LL |         x_u64 > x_usize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -213,7 +213,7 @@
    |                  ^^^^
    |                  |
    |                  expected `u128`, found `u8`
-   |                  help: you can convert an `u8` to `u128`: `x_u8.into()`
+   |                  help: you can convert a `u8` to a `u128`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:69:18
@@ -222,7 +222,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `u128`, found `u16`
-   |                  help: you can convert an `u16` to `u128`: `x_u16.into()`
+   |                  help: you can convert a `u16` to a `u128`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:71:18
@@ -231,7 +231,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `u128`, found `u32`
-   |                  help: you can convert an `u32` to `u128`: `x_u32.into()`
+   |                  help: you can convert a `u32` to a `u128`: `x_u32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:73:18
@@ -240,7 +240,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `u128`, found `u64`
-   |                  help: you can convert an `u64` to `u128`: `x_u64.into()`
+   |                  help: you can convert a `u64` to a `u128`: `x_u64.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:75:18
@@ -248,7 +248,7 @@
 LL |         x_u128 > x_usize;
    |                  ^^^^^^^ expected `u128`, found `usize`
    |
-help: you can convert an `usize` to `u128` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u128` and panic if the converted value doesn't fit
    |
 LL |         x_u128 > x_usize.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +260,7 @@
    |                   ^^^^
    |                   |
    |                   expected `usize`, found `u8`
-   |                   help: you can convert an `u8` to `usize`: `x_u8.into()`
+   |                   help: you can convert a `u8` to a `usize`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:80:19
@@ -269,7 +269,7 @@
    |                   ^^^^^
    |                   |
    |                   expected `usize`, found `u16`
-   |                   help: you can convert an `u16` to `usize`: `x_u16.into()`
+   |                   help: you can convert a `u16` to a `usize`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:82:19
@@ -277,7 +277,7 @@
 LL |         x_usize > x_u32;
    |                   ^^^^^ expected `usize`, found `u32`
    |
-help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_u32.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -288,7 +288,7 @@
 LL |         x_usize > x_u64;
    |                   ^^^^^ expected `usize`, found `u64`
    |
-help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_u64.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -299,7 +299,7 @@
 LL |         x_usize > x_u128;
    |                   ^^^^^^ expected `usize`, found `u128`
    |
-help: you can convert an `u128` to `usize` and panic if the converted value wouldn't fit
+help: you can convert a `u128` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_u128.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -366,7 +366,7 @@
    |                 ^^^^
    |                 |
    |                 expected `i16`, found `i8`
-   |                 help: you can convert an `i8` to `i16`: `x_i8.into()`
+   |                 help: you can convert an `i8` to an `i16`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:105:17
@@ -419,7 +419,7 @@
    |                 ^^^^
    |                 |
    |                 expected `i32`, found `i8`
-   |                 help: you can convert an `i8` to `i32`: `x_i8.into()`
+   |                 help: you can convert an `i8` to an `i32`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:116:17
@@ -428,7 +428,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `i32`, found `i16`
-   |                 help: you can convert an `i16` to `i32`: `x_i16.into()`
+   |                 help: you can convert an `i16` to an `i32`: `x_i16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:118:17
@@ -458,7 +458,7 @@
 LL |         x_i32 > x_isize;
    |                 ^^^^^^^ expected `i32`, found `isize`
    |
-help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit
    |
 LL |         x_i32 > x_isize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -470,7 +470,7 @@
    |                 ^^^^
    |                 |
    |                 expected `i64`, found `i8`
-   |                 help: you can convert an `i8` to `i64`: `x_i8.into()`
+   |                 help: you can convert an `i8` to an `i64`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:127:17
@@ -479,7 +479,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `i64`, found `i16`
-   |                 help: you can convert an `i16` to `i64`: `x_i16.into()`
+   |                 help: you can convert an `i16` to an `i64`: `x_i16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:129:17
@@ -488,7 +488,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `i64`, found `i32`
-   |                 help: you can convert an `i32` to `i64`: `x_i32.into()`
+   |                 help: you can convert an `i32` to an `i64`: `x_i32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:131:17
@@ -507,7 +507,7 @@
 LL |         x_i64 > x_isize;
    |                 ^^^^^^^ expected `i64`, found `isize`
    |
-help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit
    |
 LL |         x_i64 > x_isize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -519,7 +519,7 @@
    |                  ^^^^
    |                  |
    |                  expected `i128`, found `i8`
-   |                  help: you can convert an `i8` to `i128`: `x_i8.into()`
+   |                  help: you can convert an `i8` to an `i128`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:138:18
@@ -528,7 +528,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `i128`, found `i16`
-   |                  help: you can convert an `i16` to `i128`: `x_i16.into()`
+   |                  help: you can convert an `i16` to an `i128`: `x_i16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:140:18
@@ -537,7 +537,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `i128`, found `i32`
-   |                  help: you can convert an `i32` to `i128`: `x_i32.into()`
+   |                  help: you can convert an `i32` to an `i128`: `x_i32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:142:18
@@ -546,7 +546,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `i128`, found `i64`
-   |                  help: you can convert an `i64` to `i128`: `x_i64.into()`
+   |                  help: you can convert an `i64` to an `i128`: `x_i64.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:144:18
@@ -554,7 +554,7 @@
 LL |         x_i128 > x_isize;
    |                  ^^^^^^^ expected `i128`, found `isize`
    |
-help: you can convert an `isize` to `i128` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i128` and panic if the converted value doesn't fit
    |
 LL |         x_i128 > x_isize.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -566,7 +566,7 @@
    |                   ^^^^
    |                   |
    |                   expected `isize`, found `i8`
-   |                   help: you can convert an `i8` to `isize`: `x_i8.into()`
+   |                   help: you can convert an `i8` to an `isize`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:149:19
@@ -575,7 +575,7 @@
    |                   ^^^^^
    |                   |
    |                   expected `isize`, found `i16`
-   |                   help: you can convert an `i16` to `isize`: `x_i16.into()`
+   |                   help: you can convert an `i16` to an `isize`: `x_i16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:151:19
@@ -583,7 +583,7 @@
 LL |         x_isize > x_i32;
    |                   ^^^^^ expected `isize`, found `i32`
    |
-help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_i32.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -594,7 +594,7 @@
 LL |         x_isize > x_i64;
    |                   ^^^^^ expected `isize`, found `i64`
    |
-help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_i64.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -605,7 +605,7 @@
 LL |         x_isize > x_i128;
    |                   ^^^^^^ expected `isize`, found `i128`
    |
-help: you can convert an `i128` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i128` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_i128.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -616,7 +616,7 @@
 LL |         x_u8 > x_i8;
    |                ^^^^ expected `u8`, found `i8`
    |
-help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit
    |
 LL |         x_u8 > x_i8.try_into().unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -682,7 +682,7 @@
 LL |         x_u16 > x_i8;
    |                 ^^^^ expected `u16`, found `i8`
    |
-help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit
    |
 LL |         x_u16 > x_i8.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -693,7 +693,7 @@
 LL |         x_u16 > x_i16;
    |                 ^^^^^ expected `u16`, found `i16`
    |
-help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit
    |
 LL |         x_u16 > x_i16.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -737,7 +737,7 @@
 LL |         x_u16 > x_isize;
    |                 ^^^^^^^ expected `u16`, found `isize`
    |
-help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit
    |
 LL |         x_u16 > x_isize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -748,7 +748,7 @@
 LL |         x_u32 > x_i8;
    |                 ^^^^ expected `u32`, found `i8`
    |
-help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit
    |
 LL |         x_u32 > x_i8.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -759,7 +759,7 @@
 LL |         x_u32 > x_i16;
    |                 ^^^^^ expected `u32`, found `i16`
    |
-help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit
    |
 LL |         x_u32 > x_i16.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -770,7 +770,7 @@
 LL |         x_u32 > x_i32;
    |                 ^^^^^ expected `u32`, found `i32`
    |
-help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
    |
 LL |         x_u32 > x_i32.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -803,7 +803,7 @@
 LL |         x_u32 > x_isize;
    |                 ^^^^^^^ expected `u32`, found `isize`
    |
-help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit
    |
 LL |         x_u32 > x_isize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -814,7 +814,7 @@
 LL |         x_u64 > x_i8;
    |                 ^^^^ expected `u64`, found `i8`
    |
-help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit
    |
 LL |         x_u64 > x_i8.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -825,7 +825,7 @@
 LL |         x_u64 > x_i16;
    |                 ^^^^^ expected `u64`, found `i16`
    |
-help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit
    |
 LL |         x_u64 > x_i16.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -836,7 +836,7 @@
 LL |         x_u64 > x_i32;
    |                 ^^^^^ expected `u64`, found `i32`
    |
-help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit
    |
 LL |         x_u64 > x_i32.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -847,7 +847,7 @@
 LL |         x_u64 > x_i64;
    |                 ^^^^^ expected `u64`, found `i64`
    |
-help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit
    |
 LL |         x_u64 > x_i64.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -869,7 +869,7 @@
 LL |         x_u64 > x_isize;
    |                 ^^^^^^^ expected `u64`, found `isize`
    |
-help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit
    |
 LL |         x_u64 > x_isize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -880,7 +880,7 @@
 LL |         x_u128 > x_i8;
    |                  ^^^^ expected `u128`, found `i8`
    |
-help: you can convert an `i8` to `u128` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u128` and panic if the converted value doesn't fit
    |
 LL |         x_u128 > x_i8.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -891,7 +891,7 @@
 LL |         x_u128 > x_i16;
    |                  ^^^^^ expected `u128`, found `i16`
    |
-help: you can convert an `i16` to `u128` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u128` and panic if the converted value doesn't fit
    |
 LL |         x_u128 > x_i16.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -902,7 +902,7 @@
 LL |         x_u128 > x_i32;
    |                  ^^^^^ expected `u128`, found `i32`
    |
-help: you can convert an `i32` to `u128` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u128` and panic if the converted value doesn't fit
    |
 LL |         x_u128 > x_i32.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -913,7 +913,7 @@
 LL |         x_u128 > x_i64;
    |                  ^^^^^ expected `u128`, found `i64`
    |
-help: you can convert an `i64` to `u128` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `u128` and panic if the converted value doesn't fit
    |
 LL |         x_u128 > x_i64.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -924,7 +924,7 @@
 LL |         x_u128 > x_i128;
    |                  ^^^^^^ expected `u128`, found `i128`
    |
-help: you can convert an `i128` to `u128` and panic if the converted value wouldn't fit
+help: you can convert an `i128` to a `u128` and panic if the converted value doesn't fit
    |
 LL |         x_u128 > x_i128.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -935,7 +935,7 @@
 LL |         x_u128 > x_isize;
    |                  ^^^^^^^ expected `u128`, found `isize`
    |
-help: you can convert an `isize` to `u128` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u128` and panic if the converted value doesn't fit
    |
 LL |         x_u128 > x_isize.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -946,7 +946,7 @@
 LL |         x_usize > x_i8;
    |                   ^^^^ expected `usize`, found `i8`
    |
-help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_i8.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -957,7 +957,7 @@
 LL |         x_usize > x_i16;
    |                   ^^^^^ expected `usize`, found `i16`
    |
-help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_i16.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -968,7 +968,7 @@
 LL |         x_usize > x_i32;
    |                   ^^^^^ expected `usize`, found `i32`
    |
-help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_i32.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -979,7 +979,7 @@
 LL |         x_usize > x_i64;
    |                   ^^^^^ expected `usize`, found `i64`
    |
-help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_i64.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -990,7 +990,7 @@
 LL |         x_usize > x_i128;
    |                   ^^^^^^ expected `usize`, found `i128`
    |
-help: you can convert an `i128` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i128` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_i128.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1001,7 +1001,7 @@
 LL |         x_usize > x_isize;
    |                   ^^^^^^^ expected `usize`, found `isize`
    |
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         x_usize > x_isize.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1012,7 +1012,7 @@
 LL |         x_i8 > x_u8;
    |                ^^^^ expected `i8`, found `u8`
    |
-help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit
    |
 LL |         x_i8 > x_u8.try_into().unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1023,7 +1023,7 @@
 LL |         x_i8 > x_u16;
    |                ^^^^^ expected `i8`, found `u16`
    |
-help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit
    |
 LL |         x_i8 > x_u16.try_into().unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1034,7 +1034,7 @@
 LL |         x_i8 > x_u32;
    |                ^^^^^ expected `i8`, found `u32`
    |
-help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit
    |
 LL |         x_i8 > x_u32.try_into().unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1045,7 +1045,7 @@
 LL |         x_i8 > x_u64;
    |                ^^^^^ expected `i8`, found `u64`
    |
-help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit
    |
 LL |         x_i8 > x_u64.try_into().unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1056,7 +1056,7 @@
 LL |         x_i8 > x_u128;
    |                ^^^^^^ expected `i8`, found `u128`
    |
-help: you can convert an `u128` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u128` to an `i8` and panic if the converted value doesn't fit
    |
 LL |         x_i8 > x_u128.try_into().unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1067,7 +1067,7 @@
 LL |         x_i8 > x_usize;
    |                ^^^^^^^ expected `i8`, found `usize`
    |
-help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit
    |
 LL |         x_i8 > x_usize.try_into().unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1079,7 +1079,7 @@
    |                 ^^^^
    |                 |
    |                 expected `i16`, found `u8`
-   |                 help: you can convert an `u8` to `i16`: `x_u8.into()`
+   |                 help: you can convert a `u8` to an `i16`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:257:17
@@ -1087,7 +1087,7 @@
 LL |         x_i16 > x_u16;
    |                 ^^^^^ expected `i16`, found `u16`
    |
-help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit
    |
 LL |         x_i16 > x_u16.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1098,7 +1098,7 @@
 LL |         x_i16 > x_u32;
    |                 ^^^^^ expected `i16`, found `u32`
    |
-help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit
    |
 LL |         x_i16 > x_u32.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1109,7 +1109,7 @@
 LL |         x_i16 > x_u64;
    |                 ^^^^^ expected `i16`, found `u64`
    |
-help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit
    |
 LL |         x_i16 > x_u64.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1120,7 +1120,7 @@
 LL |         x_i16 > x_u128;
    |                 ^^^^^^ expected `i16`, found `u128`
    |
-help: you can convert an `u128` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `u128` to an `i16` and panic if the converted value doesn't fit
    |
 LL |         x_i16 > x_u128.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1131,7 +1131,7 @@
 LL |         x_i16 > x_usize;
    |                 ^^^^^^^ expected `i16`, found `usize`
    |
-help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit
    |
 LL |         x_i16 > x_usize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1143,7 +1143,7 @@
    |                 ^^^^
    |                 |
    |                 expected `i32`, found `u8`
-   |                 help: you can convert an `u8` to `i32`: `x_u8.into()`
+   |                 help: you can convert a `u8` to an `i32`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:270:17
@@ -1152,7 +1152,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `i32`, found `u16`
-   |                 help: you can convert an `u16` to `i32`: `x_u16.into()`
+   |                 help: you can convert a `u16` to an `i32`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:272:17
@@ -1160,7 +1160,7 @@
 LL |         x_i32 > x_u32;
    |                 ^^^^^ expected `i32`, found `u32`
    |
-help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
    |
 LL |         x_i32 > x_u32.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1171,7 +1171,7 @@
 LL |         x_i32 > x_u64;
    |                 ^^^^^ expected `i32`, found `u64`
    |
-help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit
    |
 LL |         x_i32 > x_u64.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1182,7 +1182,7 @@
 LL |         x_i32 > x_u128;
    |                 ^^^^^^ expected `i32`, found `u128`
    |
-help: you can convert an `u128` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `u128` to an `i32` and panic if the converted value doesn't fit
    |
 LL |         x_i32 > x_u128.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1193,7 +1193,7 @@
 LL |         x_i32 > x_usize;
    |                 ^^^^^^^ expected `i32`, found `usize`
    |
-help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit
    |
 LL |         x_i32 > x_usize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1205,7 +1205,7 @@
    |                 ^^^^
    |                 |
    |                 expected `i64`, found `u8`
-   |                 help: you can convert an `u8` to `i64`: `x_u8.into()`
+   |                 help: you can convert a `u8` to an `i64`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:283:17
@@ -1214,7 +1214,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `i64`, found `u16`
-   |                 help: you can convert an `u16` to `i64`: `x_u16.into()`
+   |                 help: you can convert a `u16` to an `i64`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:285:17
@@ -1223,7 +1223,7 @@
    |                 ^^^^^
    |                 |
    |                 expected `i64`, found `u32`
-   |                 help: you can convert an `u32` to `i64`: `x_u32.into()`
+   |                 help: you can convert a `u32` to an `i64`: `x_u32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:287:17
@@ -1231,7 +1231,7 @@
 LL |         x_i64 > x_u64;
    |                 ^^^^^ expected `i64`, found `u64`
    |
-help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit
    |
 LL |         x_i64 > x_u64.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1242,7 +1242,7 @@
 LL |         x_i64 > x_u128;
    |                 ^^^^^^ expected `i64`, found `u128`
    |
-help: you can convert an `u128` to `i64` and panic if the converted value wouldn't fit
+help: you can convert a `u128` to an `i64` and panic if the converted value doesn't fit
    |
 LL |         x_i64 > x_u128.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1253,7 +1253,7 @@
 LL |         x_i64 > x_usize;
    |                 ^^^^^^^ expected `i64`, found `usize`
    |
-help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit
    |
 LL |         x_i64 > x_usize.try_into().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1265,7 +1265,7 @@
    |                  ^^^^
    |                  |
    |                  expected `i128`, found `u8`
-   |                  help: you can convert an `u8` to `i128`: `x_u8.into()`
+   |                  help: you can convert a `u8` to an `i128`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:296:18
@@ -1274,7 +1274,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `i128`, found `u16`
-   |                  help: you can convert an `u16` to `i128`: `x_u16.into()`
+   |                  help: you can convert a `u16` to an `i128`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:298:18
@@ -1283,7 +1283,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `i128`, found `u32`
-   |                  help: you can convert an `u32` to `i128`: `x_u32.into()`
+   |                  help: you can convert a `u32` to an `i128`: `x_u32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:300:18
@@ -1292,7 +1292,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `i128`, found `u64`
-   |                  help: you can convert an `u64` to `i128`: `x_u64.into()`
+   |                  help: you can convert a `u64` to an `i128`: `x_u64.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:302:18
@@ -1300,7 +1300,7 @@
 LL |         x_i128 > x_u128;
    |                  ^^^^^^ expected `i128`, found `u128`
    |
-help: you can convert an `u128` to `i128` and panic if the converted value wouldn't fit
+help: you can convert a `u128` to an `i128` and panic if the converted value doesn't fit
    |
 LL |         x_i128 > x_u128.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1311,7 +1311,7 @@
 LL |         x_i128 > x_usize;
    |                  ^^^^^^^ expected `i128`, found `usize`
    |
-help: you can convert an `usize` to `i128` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i128` and panic if the converted value doesn't fit
    |
 LL |         x_i128 > x_usize.try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1323,7 +1323,7 @@
    |                   ^^^^
    |                   |
    |                   expected `isize`, found `u8`
-   |                   help: you can convert an `u8` to `isize`: `x_u8.into()`
+   |                   help: you can convert a `u8` to an `isize`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast-binop.rs:309:19
@@ -1331,7 +1331,7 @@
 LL |         x_isize > x_u16;
    |                   ^^^^^ expected `isize`, found `u16`
    |
-help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_u16.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1342,7 +1342,7 @@
 LL |         x_isize > x_u32;
    |                   ^^^^^ expected `isize`, found `u32`
    |
-help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_u32.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1353,7 +1353,7 @@
 LL |         x_isize > x_u64;
    |                   ^^^^^ expected `isize`, found `u64`
    |
-help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_u64.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1364,7 +1364,7 @@
 LL |         x_isize > x_u128;
    |                   ^^^^^^ expected `isize`, found `u128`
    |
-help: you can convert an `u128` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `u128` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_u128.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1375,7 +1375,7 @@
 LL |         x_isize > x_usize;
    |                   ^^^^^^^ expected `isize`, found `usize`
    |
-help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit
    |
 LL |         x_isize > x_usize.try_into().unwrap();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr
index cc1aa72..ffd6368 100644
--- a/src/test/ui/numeric/numeric-cast.stderr
+++ b/src/test/ui/numeric/numeric-cast.stderr
@@ -4,7 +4,7 @@
 LL |     foo::<usize>(x_u64);
    |                  ^^^^^ expected `usize`, found `u64`
    |
-help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     foo::<usize>(x_u64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@
 LL |     foo::<usize>(x_u32);
    |                  ^^^^^ expected `usize`, found `u32`
    |
-help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     foo::<usize>(x_u32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `usize`, found `u16`
-   |                  help: you can convert an `u16` to `usize`: `x_u16.into()`
+   |                  help: you can convert a `u16` to a `usize`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:29:18
@@ -36,7 +36,7 @@
    |                  ^^^^
    |                  |
    |                  expected `usize`, found `u8`
-   |                  help: you can convert an `u8` to `usize`: `x_u8.into()`
+   |                  help: you can convert a `u8` to a `usize`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:31:18
@@ -44,7 +44,7 @@
 LL |     foo::<usize>(x_isize);
    |                  ^^^^^^^ expected `usize`, found `isize`
    |
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     foo::<usize>(x_isize.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -55,7 +55,7 @@
 LL |     foo::<usize>(x_i64);
    |                  ^^^^^ expected `usize`, found `i64`
    |
-help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     foo::<usize>(x_i64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -66,7 +66,7 @@
 LL |     foo::<usize>(x_i32);
    |                  ^^^^^ expected `usize`, found `i32`
    |
-help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     foo::<usize>(x_i32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@
 LL |     foo::<usize>(x_i16);
    |                  ^^^^^ expected `usize`, found `i16`
    |
-help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     foo::<usize>(x_i16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -88,7 +88,7 @@
 LL |     foo::<usize>(x_i8);
    |                  ^^^^ expected `usize`, found `i8`
    |
-help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit
    |
 LL |     foo::<usize>(x_i8.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@
 LL |     foo::<isize>(x_usize);
    |                  ^^^^^^^ expected `isize`, found `usize`
    |
-help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     foo::<isize>(x_usize.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +110,7 @@
 LL |     foo::<isize>(x_u64);
    |                  ^^^^^ expected `isize`, found `u64`
    |
-help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     foo::<isize>(x_u64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -121,7 +121,7 @@
 LL |     foo::<isize>(x_u32);
    |                  ^^^^^ expected `isize`, found `u32`
    |
-help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     foo::<isize>(x_u32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +132,7 @@
 LL |     foo::<isize>(x_u16);
    |                  ^^^^^ expected `isize`, found `u16`
    |
-help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     foo::<isize>(x_u16.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@
    |                  ^^^^
    |                  |
    |                  expected `isize`, found `u8`
-   |                  help: you can convert an `u8` to `isize`: `x_u8.into()`
+   |                  help: you can convert a `u8` to an `isize`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:55:18
@@ -152,7 +152,7 @@
 LL |     foo::<isize>(x_i64);
    |                  ^^^^^ expected `isize`, found `i64`
    |
-help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     foo::<isize>(x_i64.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@
 LL |     foo::<isize>(x_i32);
    |                  ^^^^^ expected `isize`, found `i32`
    |
-help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit
    |
 LL |     foo::<isize>(x_i32.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -175,7 +175,7 @@
    |                  ^^^^^
    |                  |
    |                  expected `isize`, found `i16`
-   |                  help: you can convert an `i16` to `isize`: `x_i16.into()`
+   |                  help: you can convert an `i16` to an `isize`: `x_i16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:61:18
@@ -184,7 +184,7 @@
    |                  ^^^^
    |                  |
    |                  expected `isize`, found `i8`
-   |                  help: you can convert an `i8` to `isize`: `x_i8.into()`
+   |                  help: you can convert an `i8` to an `isize`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:66:16
@@ -192,7 +192,7 @@
 LL |     foo::<u64>(x_usize);
    |                ^^^^^^^ expected `u64`, found `usize`
    |
-help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
    |
 LL |     foo::<u64>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -204,7 +204,7 @@
    |                ^^^^^
    |                |
    |                expected `u64`, found `u32`
-   |                help: you can convert an `u32` to `u64`: `x_u32.into()`
+   |                help: you can convert a `u32` to a `u64`: `x_u32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:71:16
@@ -213,7 +213,7 @@
    |                ^^^^^
    |                |
    |                expected `u64`, found `u16`
-   |                help: you can convert an `u16` to `u64`: `x_u16.into()`
+   |                help: you can convert a `u16` to a `u64`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:73:16
@@ -222,7 +222,7 @@
    |                ^^^^
    |                |
    |                expected `u64`, found `u8`
-   |                help: you can convert an `u8` to `u64`: `x_u8.into()`
+   |                help: you can convert a `u8` to a `u64`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:75:16
@@ -230,7 +230,7 @@
 LL |     foo::<u64>(x_isize);
    |                ^^^^^^^ expected `u64`, found `isize`
    |
-help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit
    |
 LL |     foo::<u64>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@
 LL |     foo::<u64>(x_i64);
    |                ^^^^^ expected `u64`, found `i64`
    |
-help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit
    |
 LL |     foo::<u64>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -252,7 +252,7 @@
 LL |     foo::<u64>(x_i32);
    |                ^^^^^ expected `u64`, found `i32`
    |
-help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit
    |
 LL |     foo::<u64>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -263,7 +263,7 @@
 LL |     foo::<u64>(x_i16);
    |                ^^^^^ expected `u64`, found `i16`
    |
-help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit
    |
 LL |     foo::<u64>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -274,7 +274,7 @@
 LL |     foo::<u64>(x_i8);
    |                ^^^^ expected `u64`, found `i8`
    |
-help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit
    |
 LL |     foo::<u64>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -285,7 +285,7 @@
 LL |     foo::<i64>(x_usize);
    |                ^^^^^^^ expected `i64`, found `usize`
    |
-help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit
    |
 LL |     foo::<i64>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +296,7 @@
 LL |     foo::<i64>(x_u64);
    |                ^^^^^ expected `i64`, found `u64`
    |
-help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit
    |
 LL |     foo::<i64>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -308,7 +308,7 @@
    |                ^^^^^
    |                |
    |                expected `i64`, found `u32`
-   |                help: you can convert an `u32` to `i64`: `x_u32.into()`
+   |                help: you can convert a `u32` to an `i64`: `x_u32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:94:16
@@ -317,7 +317,7 @@
    |                ^^^^^
    |                |
    |                expected `i64`, found `u16`
-   |                help: you can convert an `u16` to `i64`: `x_u16.into()`
+   |                help: you can convert a `u16` to an `i64`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:96:16
@@ -326,7 +326,7 @@
    |                ^^^^
    |                |
    |                expected `i64`, found `u8`
-   |                help: you can convert an `u8` to `i64`: `x_u8.into()`
+   |                help: you can convert a `u8` to an `i64`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:98:16
@@ -334,7 +334,7 @@
 LL |     foo::<i64>(x_isize);
    |                ^^^^^^^ expected `i64`, found `isize`
    |
-help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit
    |
 LL |     foo::<i64>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -346,7 +346,7 @@
    |                ^^^^^
    |                |
    |                expected `i64`, found `i32`
-   |                help: you can convert an `i32` to `i64`: `x_i32.into()`
+   |                help: you can convert an `i32` to an `i64`: `x_i32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:103:16
@@ -355,7 +355,7 @@
    |                ^^^^^
    |                |
    |                expected `i64`, found `i16`
-   |                help: you can convert an `i16` to `i64`: `x_i16.into()`
+   |                help: you can convert an `i16` to an `i64`: `x_i16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:105:16
@@ -364,7 +364,7 @@
    |                ^^^^
    |                |
    |                expected `i64`, found `i8`
-   |                help: you can convert an `i8` to `i64`: `x_i8.into()`
+   |                help: you can convert an `i8` to an `i64`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:110:16
@@ -372,7 +372,7 @@
 LL |     foo::<u32>(x_usize);
    |                ^^^^^^^ expected `u32`, found `usize`
    |
-help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     foo::<u32>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -383,7 +383,7 @@
 LL |     foo::<u32>(x_u64);
    |                ^^^^^ expected `u32`, found `u64`
    |
-help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     foo::<u32>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -395,7 +395,7 @@
    |                ^^^^^
    |                |
    |                expected `u32`, found `u16`
-   |                help: you can convert an `u16` to `u32`: `x_u16.into()`
+   |                help: you can convert a `u16` to a `u32`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:117:16
@@ -404,7 +404,7 @@
    |                ^^^^
    |                |
    |                expected `u32`, found `u8`
-   |                help: you can convert an `u8` to `u32`: `x_u8.into()`
+   |                help: you can convert a `u8` to a `u32`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:119:16
@@ -412,7 +412,7 @@
 LL |     foo::<u32>(x_isize);
    |                ^^^^^^^ expected `u32`, found `isize`
    |
-help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     foo::<u32>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -423,7 +423,7 @@
 LL |     foo::<u32>(x_i64);
    |                ^^^^^ expected `u32`, found `i64`
    |
-help: you can convert an `i64` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     foo::<u32>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -434,7 +434,7 @@
 LL |     foo::<u32>(x_i32);
    |                ^^^^^ expected `u32`, found `i32`
    |
-help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     foo::<u32>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -445,7 +445,7 @@
 LL |     foo::<u32>(x_i16);
    |                ^^^^^ expected `u32`, found `i16`
    |
-help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     foo::<u32>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -456,7 +456,7 @@
 LL |     foo::<u32>(x_i8);
    |                ^^^^ expected `u32`, found `i8`
    |
-help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit
    |
 LL |     foo::<u32>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -467,7 +467,7 @@
 LL |     foo::<i32>(x_usize);
    |                ^^^^^^^ expected `i32`, found `usize`
    |
-help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     foo::<i32>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -478,7 +478,7 @@
 LL |     foo::<i32>(x_u64);
    |                ^^^^^ expected `i32`, found `u64`
    |
-help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     foo::<i32>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -489,7 +489,7 @@
 LL |     foo::<i32>(x_u32);
    |                ^^^^^ expected `i32`, found `u32`
    |
-help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     foo::<i32>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -501,7 +501,7 @@
    |                ^^^^^
    |                |
    |                expected `i32`, found `u16`
-   |                help: you can convert an `u16` to `i32`: `x_u16.into()`
+   |                help: you can convert a `u16` to an `i32`: `x_u16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:140:16
@@ -510,7 +510,7 @@
    |                ^^^^
    |                |
    |                expected `i32`, found `u8`
-   |                help: you can convert an `u8` to `i32`: `x_u8.into()`
+   |                help: you can convert a `u8` to an `i32`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:142:16
@@ -518,7 +518,7 @@
 LL |     foo::<i32>(x_isize);
    |                ^^^^^^^ expected `i32`, found `isize`
    |
-help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     foo::<i32>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -529,7 +529,7 @@
 LL |     foo::<i32>(x_i64);
    |                ^^^^^ expected `i32`, found `i64`
    |
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     foo::<i32>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -541,7 +541,7 @@
    |                ^^^^^
    |                |
    |                expected `i32`, found `i16`
-   |                help: you can convert an `i16` to `i32`: `x_i16.into()`
+   |                help: you can convert an `i16` to an `i32`: `x_i16.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:149:16
@@ -550,7 +550,7 @@
    |                ^^^^
    |                |
    |                expected `i32`, found `i8`
-   |                help: you can convert an `i8` to `i32`: `x_i8.into()`
+   |                help: you can convert an `i8` to an `i32`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:154:16
@@ -558,7 +558,7 @@
 LL |     foo::<u16>(x_usize);
    |                ^^^^^^^ expected `u16`, found `usize`
    |
-help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -569,7 +569,7 @@
 LL |     foo::<u16>(x_u64);
    |                ^^^^^ expected `u16`, found `u64`
    |
-help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -580,7 +580,7 @@
 LL |     foo::<u16>(x_u32);
    |                ^^^^^ expected `u16`, found `u32`
    |
-help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -592,7 +592,7 @@
    |                ^^^^
    |                |
    |                expected `u16`, found `u8`
-   |                help: you can convert an `u8` to `u16`: `x_u8.into()`
+   |                help: you can convert a `u8` to a `u16`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:163:16
@@ -600,7 +600,7 @@
 LL |     foo::<u16>(x_isize);
    |                ^^^^^^^ expected `u16`, found `isize`
    |
-help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -611,7 +611,7 @@
 LL |     foo::<u16>(x_i64);
    |                ^^^^^ expected `u16`, found `i64`
    |
-help: you can convert an `i64` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -622,7 +622,7 @@
 LL |     foo::<u16>(x_i32);
    |                ^^^^^ expected `u16`, found `i32`
    |
-help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -633,7 +633,7 @@
 LL |     foo::<u16>(x_i16);
    |                ^^^^^ expected `u16`, found `i16`
    |
-help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_i16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -644,7 +644,7 @@
 LL |     foo::<u16>(x_i8);
    |                ^^^^ expected `u16`, found `i8`
    |
-help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     foo::<u16>(x_i8.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -655,7 +655,7 @@
 LL |     foo::<i16>(x_usize);
    |                ^^^^^^^ expected `i16`, found `usize`
    |
-help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo::<i16>(x_usize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -666,7 +666,7 @@
 LL |     foo::<i16>(x_u64);
    |                ^^^^^ expected `i16`, found `u64`
    |
-help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo::<i16>(x_u64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -677,7 +677,7 @@
 LL |     foo::<i16>(x_u32);
    |                ^^^^^ expected `i16`, found `u32`
    |
-help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo::<i16>(x_u32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -688,7 +688,7 @@
 LL |     foo::<i16>(x_u16);
    |                ^^^^^ expected `i16`, found `u16`
    |
-help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo::<i16>(x_u16.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -700,7 +700,7 @@
    |                ^^^^
    |                |
    |                expected `i16`, found `u8`
-   |                help: you can convert an `u8` to `i16`: `x_u8.into()`
+   |                help: you can convert a `u8` to an `i16`: `x_u8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:186:16
@@ -708,7 +708,7 @@
 LL |     foo::<i16>(x_isize);
    |                ^^^^^^^ expected `i16`, found `isize`
    |
-help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo::<i16>(x_isize.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -719,7 +719,7 @@
 LL |     foo::<i16>(x_i64);
    |                ^^^^^ expected `i16`, found `i64`
    |
-help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo::<i16>(x_i64.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -730,7 +730,7 @@
 LL |     foo::<i16>(x_i32);
    |                ^^^^^ expected `i16`, found `i32`
    |
-help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit
    |
 LL |     foo::<i16>(x_i32.try_into().unwrap());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -742,7 +742,7 @@
    |                ^^^^
    |                |
    |                expected `i16`, found `i8`
-   |                help: you can convert an `i8` to `i16`: `x_i8.into()`
+   |                help: you can convert an `i8` to an `i16`: `x_i8.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:198:15
@@ -750,7 +750,7 @@
 LL |     foo::<u8>(x_usize);
    |               ^^^^^^^ expected `u8`, found `usize`
    |
-help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_usize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -761,7 +761,7 @@
 LL |     foo::<u8>(x_u64);
    |               ^^^^^ expected `u8`, found `u64`
    |
-help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_u64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -772,7 +772,7 @@
 LL |     foo::<u8>(x_u32);
    |               ^^^^^ expected `u8`, found `u32`
    |
-help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_u32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -783,7 +783,7 @@
 LL |     foo::<u8>(x_u16);
    |               ^^^^^ expected `u8`, found `u16`
    |
-help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_u16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -794,7 +794,7 @@
 LL |     foo::<u8>(x_isize);
    |               ^^^^^^^ expected `u8`, found `isize`
    |
-help: you can convert an `isize` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_isize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -805,7 +805,7 @@
 LL |     foo::<u8>(x_i64);
    |               ^^^^^ expected `u8`, found `i64`
    |
-help: you can convert an `i64` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_i64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -816,7 +816,7 @@
 LL |     foo::<u8>(x_i32);
    |               ^^^^^ expected `u8`, found `i32`
    |
-help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_i32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -827,7 +827,7 @@
 LL |     foo::<u8>(x_i16);
    |               ^^^^^ expected `u8`, found `i16`
    |
-help: you can convert an `i16` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_i16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -838,7 +838,7 @@
 LL |     foo::<u8>(x_i8);
    |               ^^^^ expected `u8`, found `i8`
    |
-help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     foo::<u8>(x_i8.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -849,7 +849,7 @@
 LL |     foo::<i8>(x_usize);
    |               ^^^^^^^ expected `i8`, found `usize`
    |
-help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_usize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -860,7 +860,7 @@
 LL |     foo::<i8>(x_u64);
    |               ^^^^^ expected `i8`, found `u64`
    |
-help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_u64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -871,7 +871,7 @@
 LL |     foo::<i8>(x_u32);
    |               ^^^^^ expected `i8`, found `u32`
    |
-help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_u32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -882,7 +882,7 @@
 LL |     foo::<i8>(x_u16);
    |               ^^^^^ expected `i8`, found `u16`
    |
-help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_u16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -893,7 +893,7 @@
 LL |     foo::<i8>(x_u8);
    |               ^^^^ expected `i8`, found `u8`
    |
-help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit
+help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_u8.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -904,7 +904,7 @@
 LL |     foo::<i8>(x_isize);
    |               ^^^^^^^ expected `i8`, found `isize`
    |
-help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_isize.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -915,7 +915,7 @@
 LL |     foo::<i8>(x_i64);
    |               ^^^^^ expected `i8`, found `i64`
    |
-help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_i64.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -926,7 +926,7 @@
 LL |     foo::<i8>(x_i32);
    |               ^^^^^ expected `i8`, found `i32`
    |
-help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_i32.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -937,7 +937,7 @@
 LL |     foo::<i8>(x_i16);
    |               ^^^^^ expected `i8`, found `i16`
    |
-help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit
+help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit
    |
 LL |     foo::<i8>(x_i16.try_into().unwrap());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -948,7 +948,7 @@
 LL |     foo::<f64>(x_usize);
    |                ^^^^^^^ expected `f64`, found `usize`
    |
-help: you can cast an `usize to `f64`, producing the floating point representation of the integer,
+help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer,
    |                                              rounded if necessary
 LL |     foo::<f64>(x_usize as f64);
    |                ^^^^^^^^^^^^^^
@@ -959,7 +959,7 @@
 LL |     foo::<f64>(x_u64);
    |                ^^^^^ expected `f64`, found `u64`
    |
-help: you can cast an `u64 to `f64`, producing the floating point representation of the integer,
+help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer,
    |                                              rounded if necessary
 LL |     foo::<f64>(x_u64 as f64);
    |                ^^^^^^^^^^^^
@@ -970,7 +970,7 @@
 LL |     foo::<f64>(x_u32);
    |                ^^^^^ expected `f64`, found `u32`
    |
-help: you can convert an `u32` to `f64`, producing the floating point representation of the integer
+help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(x_u32.into());
    |                ^^^^^^^^^^^^
@@ -981,7 +981,7 @@
 LL |     foo::<f64>(x_u16);
    |                ^^^^^ expected `f64`, found `u16`
    |
-help: you can convert an `u16` to `f64`, producing the floating point representation of the integer
+help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(x_u16.into());
    |                ^^^^^^^^^^^^
@@ -992,7 +992,7 @@
 LL |     foo::<f64>(x_u8);
    |                ^^^^ expected `f64`, found `u8`
    |
-help: you can convert an `u8` to `f64`, producing the floating point representation of the integer
+help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(x_u8.into());
    |                ^^^^^^^^^^^
@@ -1003,7 +1003,7 @@
 LL |     foo::<f64>(x_isize);
    |                ^^^^^^^ expected `f64`, found `isize`
    |
-help: you can convert an `isize` to `f64`, producing the floating point representation of the integer, rounded if necessary
+help: you can convert an `isize` to an `f64`, producing the floating point representation of the integer, rounded if necessary
    |
 LL |     foo::<f64>(x_isize as f64);
    |                ^^^^^^^^^^^^^^
@@ -1014,7 +1014,7 @@
 LL |     foo::<f64>(x_i64);
    |                ^^^^^ expected `f64`, found `i64`
    |
-help: you can convert an `i64` to `f64`, producing the floating point representation of the integer, rounded if necessary
+help: you can convert an `i64` to an `f64`, producing the floating point representation of the integer, rounded if necessary
    |
 LL |     foo::<f64>(x_i64 as f64);
    |                ^^^^^^^^^^^^
@@ -1025,7 +1025,7 @@
 LL |     foo::<f64>(x_i32);
    |                ^^^^^ expected `f64`, found `i32`
    |
-help: you can convert an `i32` to `f64`, producing the floating point representation of the integer
+help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(x_i32.into());
    |                ^^^^^^^^^^^^
@@ -1036,7 +1036,7 @@
 LL |     foo::<f64>(x_i16);
    |                ^^^^^ expected `f64`, found `i16`
    |
-help: you can convert an `i16` to `f64`, producing the floating point representation of the integer
+help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(x_i16.into());
    |                ^^^^^^^^^^^^
@@ -1047,7 +1047,7 @@
 LL |     foo::<f64>(x_i8);
    |                ^^^^ expected `f64`, found `i8`
    |
-help: you can convert an `i8` to `f64`, producing the floating point representation of the integer
+help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(x_i8.into());
    |                ^^^^^^^^^^^
@@ -1059,7 +1059,7 @@
    |                ^^^^^
    |                |
    |                expected `f64`, found `f32`
-   |                help: you can convert an `f32` to `f64`: `x_f32.into()`
+   |                help: you can convert an `f32` to an `f64`: `x_f32.into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:266:16
@@ -1067,7 +1067,7 @@
 LL |     foo::<f32>(x_usize);
    |                ^^^^^^^ expected `f32`, found `usize`
    |
-help: you can cast an `usize to `f32`, producing the floating point representation of the integer,
+help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer,
    |                                              rounded if necessary
 LL |     foo::<f32>(x_usize as f32);
    |                ^^^^^^^^^^^^^^
@@ -1078,7 +1078,7 @@
 LL |     foo::<f32>(x_u64);
    |                ^^^^^ expected `f32`, found `u64`
    |
-help: you can cast an `u64 to `f32`, producing the floating point representation of the integer,
+help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer,
    |                                              rounded if necessary
 LL |     foo::<f32>(x_u64 as f32);
    |                ^^^^^^^^^^^^
@@ -1089,7 +1089,7 @@
 LL |     foo::<f32>(x_u32);
    |                ^^^^^ expected `f32`, found `u32`
    |
-help: you can cast an `u32 to `f32`, producing the floating point representation of the integer,
+help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer,
    |                                              rounded if necessary
 LL |     foo::<f32>(x_u32 as f32);
    |                ^^^^^^^^^^^^
@@ -1100,7 +1100,7 @@
 LL |     foo::<f32>(x_u16);
    |                ^^^^^ expected `f32`, found `u16`
    |
-help: you can convert an `u16` to `f32`, producing the floating point representation of the integer
+help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(x_u16.into());
    |                ^^^^^^^^^^^^
@@ -1111,7 +1111,7 @@
 LL |     foo::<f32>(x_u8);
    |                ^^^^ expected `f32`, found `u8`
    |
-help: you can convert an `u8` to `f32`, producing the floating point representation of the integer
+help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(x_u8.into());
    |                ^^^^^^^^^^^
@@ -1122,7 +1122,7 @@
 LL |     foo::<f32>(x_isize);
    |                ^^^^^^^ expected `f32`, found `isize`
    |
-help: you can convert an `isize` to `f32`, producing the floating point representation of the integer, rounded if necessary
+help: you can convert an `isize` to an `f32`, producing the floating point representation of the integer, rounded if necessary
    |
 LL |     foo::<f32>(x_isize as f32);
    |                ^^^^^^^^^^^^^^
@@ -1133,7 +1133,7 @@
 LL |     foo::<f32>(x_i64);
    |                ^^^^^ expected `f32`, found `i64`
    |
-help: you can convert an `i64` to `f32`, producing the floating point representation of the integer, rounded if necessary
+help: you can convert an `i64` to an `f32`, producing the floating point representation of the integer, rounded if necessary
    |
 LL |     foo::<f32>(x_i64 as f32);
    |                ^^^^^^^^^^^^
@@ -1144,7 +1144,7 @@
 LL |     foo::<f32>(x_i32);
    |                ^^^^^ expected `f32`, found `i32`
    |
-help: you can convert an `i32` to `f32`, producing the floating point representation of the integer, rounded if necessary
+help: you can convert an `i32` to an `f32`, producing the floating point representation of the integer, rounded if necessary
    |
 LL |     foo::<f32>(x_i32 as f32);
    |                ^^^^^^^^^^^^
@@ -1155,7 +1155,7 @@
 LL |     foo::<f32>(x_i16);
    |                ^^^^^ expected `f32`, found `i16`
    |
-help: you can convert an `i16` to `f32`, producing the floating point representation of the integer
+help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(x_i16.into());
    |                ^^^^^^^^^^^^
@@ -1166,7 +1166,7 @@
 LL |     foo::<f32>(x_i8);
    |                ^^^^ expected `f32`, found `i8`
    |
-help: you can convert an `i8` to `f32`, producing the floating point representation of the integer
+help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(x_i8.into());
    |                ^^^^^^^^^^^
@@ -1178,7 +1178,7 @@
    |                ^^^^^^^^^^^
    |                |
    |                expected `u32`, found `u16`
-   |                help: you can convert an `u16` to `u32`: `(x_u8 as u16).into()`
+   |                help: you can convert a `u16` to a `u32`: `(x_u8 as u16).into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-cast.rs:291:16
@@ -1187,7 +1187,7 @@
    |                ^^^^^
    |                |
    |                expected `i32`, found `i8`
-   |                help: you can convert an `i8` to `i32`: `(-x_i8).into()`
+   |                help: you can convert an `i8` to an `i32`: `(-x_i8).into()`
 
 error: aborting due to 113 previous errors
 
diff --git a/src/test/ui/numeric/numeric-suffix.stderr b/src/test/ui/numeric/numeric-suffix.stderr
index 00f6e1a..a62956e 100644
--- a/src/test/ui/numeric/numeric-suffix.stderr
+++ b/src/test/ui/numeric/numeric-suffix.stderr
@@ -1236,7 +1236,7 @@
 LL |     foo::<f64>(42_u32);
    |                ^^^^^^ expected `f64`, found `u32`
    |
-help: you can convert an `u32` to `f64`, producing the floating point representation of the integer
+help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(42_u32.into());
    |                ^^^^^^^^^^^^^
@@ -1247,7 +1247,7 @@
 LL |     foo::<f64>(42_u16);
    |                ^^^^^^ expected `f64`, found `u16`
    |
-help: you can convert an `u16` to `f64`, producing the floating point representation of the integer
+help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(42_u16.into());
    |                ^^^^^^^^^^^^^
@@ -1258,7 +1258,7 @@
 LL |     foo::<f64>(42_u8);
    |                ^^^^^ expected `f64`, found `u8`
    |
-help: you can convert an `u8` to `f64`, producing the floating point representation of the integer
+help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(42_u8.into());
    |                ^^^^^^^^^^^^
@@ -1291,7 +1291,7 @@
 LL |     foo::<f64>(42_i32);
    |                ^^^^^^ expected `f64`, found `i32`
    |
-help: you can convert an `i32` to `f64`, producing the floating point representation of the integer
+help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(42_i32.into());
    |                ^^^^^^^^^^^^^
@@ -1302,7 +1302,7 @@
 LL |     foo::<f64>(42_i16);
    |                ^^^^^^ expected `f64`, found `i16`
    |
-help: you can convert an `i16` to `f64`, producing the floating point representation of the integer
+help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(42_i16.into());
    |                ^^^^^^^^^^^^^
@@ -1313,7 +1313,7 @@
 LL |     foo::<f64>(42_i8);
    |                ^^^^^ expected `f64`, found `i8`
    |
-help: you can convert an `i8` to `f64`, producing the floating point representation of the integer
+help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer
    |
 LL |     foo::<f64>(42_i8.into());
    |                ^^^^^^^^^^^^
@@ -1368,7 +1368,7 @@
 LL |     foo::<f32>(42_u16);
    |                ^^^^^^ expected `f32`, found `u16`
    |
-help: you can convert an `u16` to `f32`, producing the floating point representation of the integer
+help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(42_u16.into());
    |                ^^^^^^^^^^^^^
@@ -1379,7 +1379,7 @@
 LL |     foo::<f32>(42_u8);
    |                ^^^^^ expected `f32`, found `u8`
    |
-help: you can convert an `u8` to `f32`, producing the floating point representation of the integer
+help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(42_u8.into());
    |                ^^^^^^^^^^^^
@@ -1423,7 +1423,7 @@
 LL |     foo::<f32>(42_i16);
    |                ^^^^^^ expected `f32`, found `i16`
    |
-help: you can convert an `i16` to `f32`, producing the floating point representation of the integer
+help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(42_i16.into());
    |                ^^^^^^^^^^^^^
@@ -1434,7 +1434,7 @@
 LL |     foo::<f32>(42_i8);
    |                ^^^^^ expected `f32`, found `i8`
    |
-help: you can convert an `i8` to `f32`, producing the floating point representation of the integer
+help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer
    |
 LL |     foo::<f32>(42_i8.into());
    |                ^^^^^^^^^^^^
@@ -1457,7 +1457,7 @@
    |                ^^^^^^^^^^^^
    |                |
    |                expected `u32`, found `u16`
-   |                help: you can convert an `u16` to `u32`: `(42_u8 as u16).into()`
+   |                help: you can convert a `u16` to a `u32`: `(42_u8 as u16).into()`
 
 error[E0308]: mismatched types
   --> $DIR/numeric-suffix.rs:296:16
@@ -1466,7 +1466,7 @@
    |                ^^^^^^
    |                |
    |                expected `i32`, found `i8`
-   |                help: you can convert an `i8` to `i32`: `(-42_i8).into()`
+   |                help: you can convert an `i8` to an `i32`: `(-42_i8).into()`
 
 error: aborting due to 134 previous errors
 
diff --git a/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
index 890acde..35ec586 100644
--- a/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
+++ b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
@@ -1,15 +1,17 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-associated-consts.rs:12:30
    |
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `X` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-associated-consts.rs:9:11
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     const X: usize;
-   |           - ...because it contains this associated `const`
-...
-LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `X` to another trait
+   |           ^ ...because it contains this associated `const`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr
index c32038b..d51734e 100644
--- a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr
+++ b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr
@@ -1,15 +1,17 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-associated-consts.rs:14:5
    |
+LL |     t
+   |     ^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `X` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-associated-consts.rs:9:11
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     const X: usize;
-   |           - ...because it contains this associated `const`
-...
-LL |     t
-   |     ^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `X` to another trait
+   |           ^ ...because it contains this associated `const`
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T`
    = note: required by cast to type `&dyn Bar`
 
diff --git a/src/test/ui/object-safety/object-safety-bounds.rs b/src/test/ui/object-safety/object-safety-bounds.rs
new file mode 100644
index 0000000..44bd369
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-bounds.rs
@@ -0,0 +1,12 @@
+// Traits with bounds mentioning `Self` are not object safe
+
+trait X {
+    type U: PartialEq<Self>;
+}
+
+fn f() -> Box<dyn X<U = u32>> {
+    //~^ ERROR the trait `X` cannot be made into an object
+    loop {}
+}
+
+fn main() {}
diff --git a/src/test/ui/object-safety/object-safety-bounds.stderr b/src/test/ui/object-safety/object-safety-bounds.stderr
new file mode 100644
index 0000000..89c4f8c
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-bounds.stderr
@@ -0,0 +1,17 @@
+error[E0038]: the trait `X` cannot be made into an object
+  --> $DIR/object-safety-bounds.rs:7:11
+   |
+LL | fn f() -> Box<dyn X<U = u32>> {
+   |           ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-bounds.rs:4:13
+   |
+LL | trait X {
+   |       - this trait cannot be made into an object...
+LL |     type U: PartialEq<Self>;
+   |             ^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-generics.curr.stderr b/src/test/ui/object-safety/object-safety-generics.curr.stderr
index 9e70abb..8d6094c 100644
--- a/src/test/ui/object-safety/object-safety-generics.curr.stderr
+++ b/src/test/ui/object-safety/object-safety-generics.curr.stderr
@@ -1,28 +1,32 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-generics.rs:18:30
    |
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `bar` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-generics.rs:10:8
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     fn bar<T>(&self, t: T);
-   |        --- ...because method `bar` has generic type parameters
-...
-LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `bar` to another trait
+   |        ^^^ ...because method `bar` has generic type parameters
 
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-generics.rs:24:39
    |
+LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
+   |                                       ^^^^^^^^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `bar` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-generics.rs:10:8
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     fn bar<T>(&self, t: T);
-   |        --- ...because method `bar` has generic type parameters
-...
-LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
-   |                                       ^^^^^^^^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `bar` to another trait
+   |        ^^^ ...because method `bar` has generic type parameters
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr
index 7c104fa..3d2b2bb 100644
--- a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr
+++ b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr
@@ -1,30 +1,34 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-generics.rs:20:5
    |
+LL |     t
+   |     ^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `bar` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-generics.rs:10:8
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     fn bar<T>(&self, t: T);
-   |        --- ...because method `bar` has generic type parameters
-...
-LL |     t
-   |     ^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `bar` to another trait
+   |        ^^^ ...because method `bar` has generic type parameters
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T`
    = note: required by cast to type `&dyn Bar`
 
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-generics.rs:26:5
    |
+LL |     t as &dyn Bar
+   |     ^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `bar` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-generics.rs:10:8
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     fn bar<T>(&self, t: T);
-   |        --- ...because method `bar` has generic type parameters
-...
-LL |     t as &dyn Bar
-   |     ^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `bar` to another trait
+   |        ^^^ ...because method `bar` has generic type parameters
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T`
    = note: required by cast to type `&dyn Bar`
 
diff --git a/src/test/ui/object-safety/object-safety-issue-22040.stderr b/src/test/ui/object-safety/object-safety-issue-22040.stderr
index fe9ca5b..0262d53 100644
--- a/src/test/ui/object-safety/object-safety-issue-22040.stderr
+++ b/src/test/ui/object-safety/object-safety-issue-22040.stderr
@@ -1,13 +1,16 @@
 error[E0038]: the trait `Expr` cannot be made into an object
   --> $DIR/object-safety-issue-22040.rs:12:23
    |
+LL |     elements: Vec<Box<dyn Expr + 'x>>,
+   |                       ^^^^^^^^^^^^^ `Expr` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-issue-22040.rs:5:21
+   |
 LL | trait Expr: Debug + PartialEq {
-   |       ----          --------- ...because it uses `Self` as a type parameter in this
+   |       ----          ^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     elements: Vec<Box<dyn Expr + 'x>>,
-   |                       ^^^^^^^^^^^^^ the trait `Expr` cannot be made into an object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
index 4dbb27b..3369297 100644
--- a/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
@@ -1,28 +1,32 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-mentions-Self.rs:22:30
    |
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `bar` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-mentions-Self.rs:11:22
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     fn bar(&self, x: &Self);
-   |                      ----- ...because method `bar` references the `Self` type in this parameter
-...
-LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `bar` to another trait
+   |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
 
 error[E0038]: the trait `Baz` cannot be made into an object
   --> $DIR/object-safety-mentions-Self.rs:28:30
    |
+LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
+   |                              ^^^^^^^^ `Baz` cannot be made into an object
+   |
+   = help: consider moving `baz` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-mentions-Self.rs:15:22
+   |
 LL | trait Baz {
    |       --- this trait cannot be made into an object...
 LL |     fn baz(&self) -> Self;
-   |                      ---- ...because method `baz` references the `Self` type in its return type
-...
-LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-   |                              ^^^^^^^^ the trait `Baz` cannot be made into an object
-   |
-   = help: consider moving `baz` to another trait
+   |                      ^^^^ ...because method `baz` references the `Self` type in its return type
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr
index ced2688..6e7896e 100644
--- a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr
@@ -1,30 +1,34 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-mentions-Self.rs:24:5
    |
+LL |     t
+   |     ^ `Bar` cannot be made into an object
+   |
+   = help: consider moving `bar` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-mentions-Self.rs:11:22
+   |
 LL | trait Bar {
    |       --- this trait cannot be made into an object...
 LL |     fn bar(&self, x: &Self);
-   |                      ----- ...because method `bar` references the `Self` type in this parameter
-...
-LL |     t
-   |     ^ the trait `Bar` cannot be made into an object
-   |
-   = help: consider moving `bar` to another trait
+   |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T`
    = note: required by cast to type `&dyn Bar`
 
 error[E0038]: the trait `Baz` cannot be made into an object
   --> $DIR/object-safety-mentions-Self.rs:30:5
    |
+LL |     t
+   |     ^ `Baz` cannot be made into an object
+   |
+   = help: consider moving `baz` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-mentions-Self.rs:15:22
+   |
 LL | trait Baz {
    |       --- this trait cannot be made into an object...
 LL |     fn baz(&self) -> Self;
-   |                      ---- ...because method `baz` references the `Self` type in its return type
-...
-LL |     t
-   |     ^ the trait `Baz` cannot be made into an object
-   |
-   = help: consider moving `baz` to another trait
+   |                      ^^^^ ...because method `baz` references the `Self` type in its return type
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Baz>` for `&T`
    = note: required by cast to type `&dyn Baz`
 
diff --git a/src/test/ui/object-safety/object-safety-no-static.curr.stderr b/src/test/ui/object-safety/object-safety-no-static.curr.stderr
index f878cf8..e00d6bb 100644
--- a/src/test/ui/object-safety/object-safety-no-static.curr.stderr
+++ b/src/test/ui/object-safety/object-safety-no-static.curr.stderr
@@ -1,15 +1,21 @@
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/object-safety-no-static.rs:12:18
    |
+LL | fn diverges() -> Box<dyn Foo> {
+   |                  ^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-no-static.rs:9:8
+   |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
 LL |     fn foo() {}
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL | fn diverges() -> Box<dyn Foo> {
-   |                  ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+help: consider turning `foo` into a method by giving it a `&self` argument
    |
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn foo(&self) {}
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() where Self: Sized {}
    |              ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr
index 8e92069..91a071f 100644
--- a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr
+++ b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr
@@ -1,17 +1,23 @@
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/object-safety-no-static.rs:22:27
    |
+LL |     let b: Box<dyn Foo> = Box::new(Bar);
+   |                           ^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-no-static.rs:9:8
+   |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
 LL |     fn foo() {}
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL |     let b: Box<dyn Foo> = Box::new(Bar);
-   |                           ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
-   |
+   |        ^^^ ...because associated function `foo` has no `self` parameter
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Foo>>` for `Box<Bar>`
    = note: required by cast to type `Box<dyn Foo>`
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+help: consider turning `foo` into a method by giving it a `&self` argument
+   |
+LL |     fn foo(&self) {}
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() where Self: Sized {}
    |              ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/object-safety/object-safety-sized-2.curr.stderr b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr
index 2f605d8..71236c8 100644
--- a/src/test/ui/object-safety/object-safety-sized-2.curr.stderr
+++ b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr
@@ -1,13 +1,16 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-sized-2.rs:14:30
    |
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-sized-2.rs:9:18
+   |
 LL | trait Bar
    |       --- this trait cannot be made into an object...
 LL |     where Self : Sized
-   |                  ----- ...because it requires `Self: Sized`
-...
-LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ the trait `Bar` cannot be made into an object
+   |                  ^^^^^ ...because it requires `Self: Sized`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr
index cc0463f..b6e4903 100644
--- a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr
+++ b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr
@@ -1,14 +1,16 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-sized-2.rs:16:5
    |
+LL |     t
+   |     ^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-sized-2.rs:9:18
+   |
 LL | trait Bar
    |       --- this trait cannot be made into an object...
 LL |     where Self : Sized
-   |                  ----- ...because it requires `Self: Sized`
-...
-LL |     t
-   |     ^ the trait `Bar` cannot be made into an object
-   |
+   |                  ^^^^^ ...because it requires `Self: Sized`
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T`
    = note: required by cast to type `&dyn Bar`
 
diff --git a/src/test/ui/object-safety/object-safety-sized.curr.stderr b/src/test/ui/object-safety/object-safety-sized.curr.stderr
index 54f65c4..94b06ee 100644
--- a/src/test/ui/object-safety/object-safety-sized.curr.stderr
+++ b/src/test/ui/object-safety/object-safety-sized.curr.stderr
@@ -1,13 +1,16 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-sized.rs:12:30
    |
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                              ^^^^^^^^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-sized.rs:8:13
+   |
 LL | trait Bar : Sized {
-   |       ---   ----- ...because it requires `Self: Sized`
+   |       ---   ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-   |                              ^^^^^^^^ the trait `Bar` cannot be made into an object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr
index aceacac..645852c 100644
--- a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr
+++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr
@@ -1,14 +1,16 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/object-safety-sized.rs:14:5
    |
+LL |     t
+   |     ^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-sized.rs:8:13
+   |
 LL | trait Bar : Sized {
-   |       ---   ----- ...because it requires `Self: Sized`
+   |       ---   ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     t
-   |     ^ the trait `Bar` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T`
    = note: required by cast to type `&dyn Bar`
 
diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr
index ef7f6ba..a106ab9 100644
--- a/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr
+++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-Self.stderr
@@ -1,13 +1,16 @@
 error[E0038]: the trait `Baz` cannot be made into an object
   --> $DIR/object-safety-supertrait-mentions-Self.rs:15:31
    |
+LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
+   |                               ^^^^^^^ `Baz` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-safety-supertrait-mentions-Self.rs:8:13
+   |
 LL | trait Baz : Bar<Self> {
-   |       ---   --------- ...because it uses `Self` as a type parameter in this
+   |       ---   ^^^^^^^^^ ...because it uses `Self` as a type parameter
    |       |
    |       this trait cannot be made into an object...
-...
-LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-   |                               ^^^^^^^ the trait `Baz` cannot be made into an object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/option-unwrap.rs b/src/test/ui/option-unwrap.rs
deleted file mode 100644
index 173f803..0000000
--- a/src/test/ui/option-unwrap.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// run-pass
-
-#![allow(non_camel_case_types)]
-use std::cell::Cell;
-
-struct dtor<'a> {
-    x: &'a Cell<isize>,
-}
-
-impl<'a> Drop for dtor<'a> {
-    fn drop(&mut self) {
-        self.x.set(self.x.get() - 1);
-    }
-}
-
-fn unwrap<T>(o: Option<T>) -> T {
-    match o {
-      Some(v) => v,
-      None => panic!()
-    }
-}
-
-pub fn main() {
-    let x = &Cell::new(1);
-
-    {
-        let b = Some(dtor { x:x });
-        let _c = unwrap(b);
-    }
-
-    assert_eq!(x.get(), 0);
-}
diff --git a/src/test/ui/orphan-check-diagnostics.stderr b/src/test/ui/orphan-check-diagnostics.stderr
index c84d401..7a7cea5 100644
--- a/src/test/ui/orphan-check-diagnostics.stderr
+++ b/src/test/ui/orphan-check-diagnostics.stderr
@@ -4,7 +4,7 @@
 LL | impl<T> RemoteTrait for T where T: LocalTrait {}
    |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to previous error
diff --git a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr
index 16df31b..fca9866 100644
--- a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr
+++ b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/panics/panic-safe.rs b/src/test/ui/panics/panic-safe.rs
deleted file mode 100644
index 9867cc5..0000000
--- a/src/test/ui/panics/panic-safe.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// run-pass
-#![allow(dead_code)]
-
-use std::panic::{UnwindSafe, AssertUnwindSafe};
-use std::cell::RefCell;
-use std::sync::{Mutex, RwLock, Arc};
-use std::rc::Rc;
-
-struct Foo { a: i32 }
-
-fn assert<T: UnwindSafe + ?Sized>() {}
-
-fn main() {
-    assert::<i32>();
-    assert::<&i32>();
-    assert::<*mut i32>();
-    assert::<*const i32>();
-    assert::<usize>();
-    assert::<str>();
-    assert::<&str>();
-    assert::<Foo>();
-    assert::<&Foo>();
-    assert::<Vec<i32>>();
-    assert::<String>();
-    assert::<RefCell<i32>>();
-    assert::<Box<i32>>();
-    assert::<Mutex<i32>>();
-    assert::<RwLock<i32>>();
-    assert::<&Mutex<i32>>();
-    assert::<&RwLock<i32>>();
-    assert::<Rc<i32>>();
-    assert::<Arc<i32>>();
-    assert::<Box<[u8]>>();
-
-    trait Trait: UnwindSafe {}
-    assert::<Box<dyn Trait>>();
-
-    fn bar<T>() {
-        assert::<Mutex<T>>();
-        assert::<RwLock<T>>();
-    }
-    fn baz<T: UnwindSafe>() {
-        assert::<Box<T>>();
-        assert::<Vec<T>>();
-        assert::<RefCell<T>>();
-        assert::<AssertUnwindSafe<T>>();
-        assert::<&AssertUnwindSafe<T>>();
-        assert::<Rc<AssertUnwindSafe<T>>>();
-        assert::<Arc<AssertUnwindSafe<T>>>();
-    }
-}
diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr
index bc3054c..7ae092c 100644
--- a/src/test/ui/parser/assoc-static-semantic-fail.stderr
+++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr
@@ -170,6 +170,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error: aborting due to 24 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/parser/bare-struct-body.rs b/src/test/ui/parser/bare-struct-body.rs
new file mode 100644
index 0000000..a557e86
--- /dev/null
+++ b/src/test/ui/parser/bare-struct-body.rs
@@ -0,0 +1,15 @@
+struct Foo {
+    val: (),
+}
+
+fn foo() -> Foo { //~ ERROR struct literal body without path
+    val: (),
+}
+
+fn main() {
+    let x = foo();
+    x.val == 42; //~ ERROR mismatched types
+    let x = { //~ ERROR struct literal body without path
+        val: (),
+    };
+}
diff --git a/src/test/ui/parser/bare-struct-body.stderr b/src/test/ui/parser/bare-struct-body.stderr
new file mode 100644
index 0000000..df10b0e
--- /dev/null
+++ b/src/test/ui/parser/bare-struct-body.stderr
@@ -0,0 +1,41 @@
+error: struct literal body without path
+  --> $DIR/bare-struct-body.rs:5:17
+   |
+LL |   fn foo() -> Foo {
+   |  _________________^
+LL | |     val: (),
+LL | | }
+   | |_^
+   |
+help: you might have forgotten to add the struct literal inside the block
+   |
+LL | fn foo() -> Foo { SomeStruct {
+LL |     val: (),
+LL | } }
+   |
+
+error: struct literal body without path
+  --> $DIR/bare-struct-body.rs:12:13
+   |
+LL |       let x = {
+   |  _____________^
+LL | |         val: (),
+LL | |     };
+   | |_____^
+   |
+help: you might have forgotten to add the struct literal inside the block
+   |
+LL |     let x = { SomeStruct {
+LL |         val: (),
+LL |     } };
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/bare-struct-body.rs:11:14
+   |
+LL |     x.val == 42;
+   |              ^^ expected `()`, found integer
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/bind-struct-early-modifiers.stderr b/src/test/ui/parser/bind-struct-early-modifiers.stderr
index 03482a4..b35762a 100644
--- a/src/test/ui/parser/bind-struct-early-modifiers.stderr
+++ b/src/test/ui/parser/bind-struct-early-modifiers.stderr
@@ -1,8 +1,10 @@
 error: expected `,`
-  --> $DIR/bind-struct-early-modifiers.rs:4:19
+  --> $DIR/bind-struct-early-modifiers.rs:4:20
    |
 LL |         Foo { ref x: ref x } => {},
-   |                   ^
+   |         ---        ^
+   |         |
+   |         while parsing the fields for this pattern
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr
index dea3566..5b763ae 100644
--- a/src/test/ui/parser/default.stderr
+++ b/src/test/ui/parser/default.stderr
@@ -31,6 +31,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0046]: not all trait items implemented, missing: `foo`
   --> $DIR/default.rs:22:1
diff --git a/src/test/ui/parser/float-field.stderr b/src/test/ui/parser/float-field.stderr
index 62202b9..7090efc 100644
--- a/src/test/ui/parser/float-field.stderr
+++ b/src/test/ui/parser/float-field.stderr
@@ -271,10 +271,10 @@
    = note: available fields are: `0`, `1`
 
 error[E0609]: no field `1e1` on type `(u8, u8)`
-  --> $DIR/float-field.rs:9:7
+  --> $DIR/float-field.rs:9:9
    |
 LL |     s.1.1e1;
-   |       ^^^^^
+   |         ^^^
 
 error[E0609]: no field `0x1e1` on type `S`
   --> $DIR/float-field.rs:24:7
@@ -288,7 +288,7 @@
   --> $DIR/float-field.rs:25:7
    |
 LL |     s.0x1.;
-   |       ^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -296,7 +296,7 @@
   --> $DIR/float-field.rs:28:7
    |
 LL |     s.0x1.1;
-   |       ^^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -304,7 +304,7 @@
   --> $DIR/float-field.rs:30:7
    |
 LL |     s.0x1.1e1;
-   |       ^^^^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index 6d3fc3c..c327667 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -12,7 +12,6 @@
     extern "C" fn ff4() {} // OK.
     const async unsafe extern "C" fn ff5() {} // OK.
     //~^ ERROR functions cannot be both `const` and `async`
-    //~| ERROR `from_generator` is not yet stable as a const fn
 
     trait X {
         async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
@@ -35,7 +34,6 @@
         const async unsafe extern "C" fn ft5() {}
         //~^ ERROR functions in traits cannot be declared `async`
         //~| ERROR functions in traits cannot be declared const
-        //~| ERROR `from_generator` is not yet stable as a const fn
         //~| ERROR method `ft5` has an incompatible type for trait
         //~| ERROR functions cannot be both `const` and `async`
     }
@@ -47,7 +45,6 @@
         extern "C" fn fi4() {} // OK.
         const async unsafe extern "C" fn fi5() {}
         //~^ ERROR functions cannot be both `const` and `async`
-        //~| ERROR `from_generator` is not yet stable as a const fn
     }
 
     extern {
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index f1e2188..4193b3e 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -8,7 +8,7 @@
    |     `const` because of this
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:18:9
+  --> $DIR/fn-header-semantic-fail.rs:17:9
    |
 LL |         async fn ft1();
    |         -----^^^^^^^^^^
@@ -19,19 +19,19 @@
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:20:9
+  --> $DIR/fn-header-semantic-fail.rs:19:9
    |
 LL |         const fn ft3();
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:22:9
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^ functions in traits cannot be const
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:22:9
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:22:9
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^-^^^^^----------------------------
@@ -51,7 +51,7 @@
    |         `const` because of this
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:30:9
+  --> $DIR/fn-header-semantic-fail.rs:29:9
    |
 LL |         async fn ft1() {}
    |         -----^^^^^^^^^^^^
@@ -62,19 +62,19 @@
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:32:9
    |
 LL |         const fn ft3() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:35:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:35:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:35:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -94,7 +94,7 @@
    |         `const` because of this
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:48:9
+  --> $DIR/fn-header-semantic-fail.rs:46:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -103,7 +103,7 @@
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:54:18
+  --> $DIR/fn-header-semantic-fail.rs:51:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -113,7 +113,7 @@
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:55:19
+  --> $DIR/fn-header-semantic-fail.rs:52:19
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -124,7 +124,7 @@
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:56:18
+  --> $DIR/fn-header-semantic-fail.rs:53:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -135,7 +135,7 @@
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:57:23
+  --> $DIR/fn-header-semantic-fail.rs:54:23
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -146,7 +146,7 @@
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:58:42
+  --> $DIR/fn-header-semantic-fail.rs:55:42
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -157,7 +157,7 @@
    |         help: remove the qualifiers: `fn`
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:58:9
+  --> $DIR/fn-header-semantic-fail.rs:55:9
    |
 LL |         const async unsafe extern "C" fn fe5();
    |         ^^^^^-^^^^^----------------------------
@@ -165,16 +165,8 @@
    |         |     `async` because of this
    |         `const` because of this
 
-error: `from_generator` is not yet stable as a const fn
-  --> $DIR/fn-header-semantic-fail.rs:13:44
-   |
-LL |     const async unsafe extern "C" fn ff5() {} // OK.
-   |                                            ^^
-   |
-   = help: add `#![feature(gen_future)]` to the crate attributes to enable
-
 error[E0053]: method `ft1` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:30:24
+  --> $DIR/fn-header-semantic-fail.rs:29:24
    |
 LL |         async fn ft1();
    |                       - type in trait
@@ -189,7 +181,7 @@
               found fn pointer `fn() -> impl Future`
 
 error[E0053]: method `ft5` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:35:48
+  --> $DIR/fn-header-semantic-fail.rs:34:48
    |
 LL |         const async unsafe extern "C" fn ft5();
    |                                               - type in trait
@@ -203,23 +195,7 @@
    = note: expected fn pointer `unsafe extern "C" fn()`
               found fn pointer `unsafe extern "C" fn() -> impl Future`
 
-error: `from_generator` is not yet stable as a const fn
-  --> $DIR/fn-header-semantic-fail.rs:35:48
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |                                                ^^
-   |
-   = help: add `#![feature(gen_future)]` to the crate attributes to enable
-
-error: `from_generator` is not yet stable as a const fn
-  --> $DIR/fn-header-semantic-fail.rs:48:48
-   |
-LL |         const async unsafe extern "C" fn fi5() {}
-   |                                                ^^
-   |
-   = help: add `#![feature(gen_future)]` to the crate attributes to enable
-
-error: aborting due to 23 previous errors
+error: aborting due to 20 previous errors
 
 Some errors have detailed explanations: E0053, E0379, E0706.
 For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/parser/issue-10392.stderr b/src/test/ui/parser/issue-10392.stderr
index 3499115..438ea67 100644
--- a/src/test/ui/parser/issue-10392.stderr
+++ b/src/test/ui/parser/issue-10392.stderr
@@ -2,7 +2,9 @@
   --> $DIR/issue-10392.rs:6:13
    |
 LL |     let A { , } = a();
-   |             ^ expected identifier
+   |         -   ^ expected identifier
+   |         |
+   |         while parsing the fields for this pattern
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.stderr b/src/test/ui/parser/issue-23620-invalid-escapes.stderr
index b391ac7..8c924ad0 100644
--- a/src/test/ui/parser/issue-23620-invalid-escapes.stderr
+++ b/src/test/ui/parser/issue-23620-invalid-escapes.stderr
@@ -80,9 +80,9 @@
   --> $DIR/issue-23620-invalid-escapes.rs:32:14
    |
 LL |     let _ = "\u8f";
-   |              ^^--
-   |                |
-   |                help: format of unicode escape sequences uses braces: `\u{8f}`
+   |              ^^^-
+   |              |
+   |              help: format of unicode escape sequences uses braces: `\u{8f}`
 
 error: aborting due to 13 previous errors
 
diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr
index 396aec8..80e9ac5 100644
--- a/src/test/ui/parser/issue-63135.stderr
+++ b/src/test/ui/parser/issue-63135.stderr
@@ -35,7 +35,9 @@
   --> $DIR/issue-63135.rs:3:16
    |
 LL | fn i(n{...,f #
-   |                ^ expected one of `!` or `[`
+   |      -         ^ expected one of `!` or `[`
+   |      |
+   |      while parsing the fields for this pattern
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/parser/recover-range-pats.rs b/src/test/ui/parser/recover-range-pats.rs
index e07ea62..7412b62 100644
--- a/src/test/ui/parser/recover-range-pats.rs
+++ b/src/test/ui/parser/recover-range-pats.rs
@@ -17,8 +17,8 @@
     if let 0..Y = 0 {} // OK.
     if let X..3 = 0 {} // OK.
     if let X..Y = 0 {} // OK.
-    if let true..Y = 0 {} //~ ERROR only char and numeric types
-    if let X..true = 0 {} //~ ERROR only char and numeric types
+    if let true..Y = 0 {} //~ ERROR only `char` and numeric types
+    if let X..true = 0 {} //~ ERROR only `char` and numeric types
     if let .0..Y = 0 {} //~ ERROR mismatched types
     //~^ ERROR float literals must have an integer part
     if let X.. .0 = 0 {} //~ ERROR mismatched types
@@ -30,8 +30,8 @@
     if let 0..=Y = 0 {} // OK.
     if let X..=3 = 0 {} // OK.
     if let X..=Y = 0 {} // OK.
-    if let true..=Y = 0 {} //~ ERROR only char and numeric types
-    if let X..=true = 0 {} //~ ERROR only char and numeric types
+    if let true..=Y = 0 {} //~ ERROR only `char` and numeric types
+    if let X..=true = 0 {} //~ ERROR only `char` and numeric types
     if let .0..=Y = 0 {} //~ ERROR mismatched types
     //~^ ERROR float literals must have an integer part
     if let X..=.0 = 0 {} //~ ERROR mismatched types
@@ -43,9 +43,9 @@
     if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated
     if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated
     if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated
-    if let true...Y = 0 {} //~ ERROR only char and numeric types
+    if let true...Y = 0 {} //~ ERROR only `char` and numeric types
     //~^ ERROR `...` range patterns are deprecated
-    if let X...true = 0 {} //~ ERROR only char and numeric types
+    if let X...true = 0 {} //~ ERROR only `char` and numeric types
     //~^ ERROR `...` range patterns are deprecated
     if let .0...Y = 0 {} //~ ERROR mismatched types
     //~^ ERROR float literals must have an integer part
@@ -59,7 +59,7 @@
     if let 0.. = 0 {}
     if let X.. = 0 {}
     if let true.. = 0 {}
-    //~^ ERROR only char and numeric types
+    //~^ ERROR only `char` and numeric types
     if let .0.. = 0 {}
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
@@ -69,7 +69,7 @@
     if let 0..= = 0 {} //~ ERROR inclusive range with no end
     if let X..= = 0 {} //~ ERROR inclusive range with no end
     if let true..= = 0 {} //~ ERROR inclusive range with no end
-    //~| ERROR only char and numeric types
+    //~| ERROR only `char` and numeric types
     if let .0..= = 0 {} //~ ERROR inclusive range with no end
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
@@ -79,7 +79,7 @@
     if let 0... = 0 {} //~ ERROR inclusive range with no end
     if let X... = 0 {} //~ ERROR inclusive range with no end
     if let true... = 0 {} //~ ERROR inclusive range with no end
-    //~| ERROR only char and numeric types
+    //~| ERROR only `char` and numeric types
     if let .0... = 0 {} //~ ERROR inclusive range with no end
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
@@ -89,7 +89,7 @@
     if let ..0 = 0 {}
     if let ..Y = 0 {}
     if let ..true = 0 {}
-    //~^ ERROR only char and numeric types
+    //~^ ERROR only `char` and numeric types
     if let .. .0 = 0 {}
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
@@ -99,7 +99,7 @@
     if let ..=3 = 0 {}
     if let ..=Y = 0 {}
     if let ..=true = 0 {}
-    //~^ ERROR only char and numeric types
+    //~^ ERROR only `char` and numeric types
     if let ..=.0 = 0 {}
     //~^ ERROR float literals must have an integer part
     //~| ERROR mismatched types
@@ -112,7 +112,7 @@
     //~^ ERROR range-to patterns with `...` are not allowed
     if let ...true = 0 {}
     //~^ ERROR range-to patterns with `...` are not allowed
-    //~| ERROR only char and numeric types
+    //~| ERROR only `char` and numeric types
     if let ....3 = 0 {}
     //~^ ERROR float literals must have an integer part
     //~| ERROR range-to patterns with `...` are not allowed
diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr
index 0d4db74..e351a97 100644
--- a/src/test/ui/parser/recover-range-pats.stderr
+++ b/src/test/ui/parser/recover-range-pats.stderr
@@ -258,7 +258,7 @@
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:20:12
    |
 LL |     if let true..Y = 0 {}
@@ -266,7 +266,7 @@
    |            |
    |            this is of type `bool` but it should be `char` or numeric
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:21:15
    |
 LL |     if let X..true = 0 {}
@@ -291,7 +291,7 @@
    |            |   expected integer, found floating-point number
    |            this is of type `u8`
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:33:12
    |
 LL |     if let true..=Y = 0 {}
@@ -299,7 +299,7 @@
    |            |
    |            this is of type `bool` but it should be `char` or numeric
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:34:16
    |
 LL |     if let X..=true = 0 {}
@@ -324,7 +324,7 @@
    |            |   expected integer, found floating-point number
    |            this is of type `u8`
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:46:12
    |
 LL |     if let true...Y = 0 {}
@@ -332,7 +332,7 @@
    |            |
    |            this is of type `bool` but it should be `char` or numeric
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:48:16
    |
 LL |     if let X...true = 0 {}
@@ -357,7 +357,7 @@
    |            |    expected integer, found floating-point number
    |            this is of type `u8`
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:61:12
    |
 LL |     if let true.. = 0 {}
@@ -369,7 +369,7 @@
 LL |     if let .0.. = 0 {}
    |            ^^ expected integer, found floating-point number
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:71:12
    |
 LL |     if let true..= = 0 {}
@@ -381,7 +381,7 @@
 LL |     if let .0..= = 0 {}
    |            ^^ expected integer, found floating-point number
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:81:12
    |
 LL |     if let true... = 0 {}
@@ -393,7 +393,7 @@
 LL |     if let .0... = 0 {}
    |            ^^ expected integer, found floating-point number
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:91:14
    |
 LL |     if let ..true = 0 {}
@@ -405,7 +405,7 @@
 LL |     if let .. .0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:101:15
    |
 LL |     if let ..=true = 0 {}
@@ -417,7 +417,7 @@
 LL |     if let ..=.0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:113:15
    |
 LL |     if let ...true = 0 {}
diff --git a/src/test/ui/parser/struct-literal-in-for.stderr b/src/test/ui/parser/struct-literal-in-for.stderr
index 42f5f1e..fe9c113 100644
--- a/src/test/ui/parser/struct-literal-in-for.stderr
+++ b/src/test/ui/parser/struct-literal-in-for.stderr
@@ -24,6 +24,7 @@
    | |__________^ `bool` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `bool`
+   = note: required because of the requirements on the impl of `IntoIterator` for `bool`
    = note: required by `into_iter`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
index e8ff93f..cdc9ee8 100644
--- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
+++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
@@ -54,6 +54,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error: aborting due to 6 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
index 21992a2..3f3ddfe 100644
--- a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
+++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -2,205 +2,205 @@
   --> $DIR/variadic-ffi-semantic-restrictions.rs:5:19
    |
 LL | fn f1_1(x: isize, ...) {}
-   |                   ^^^^
+   |                   ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
    |
 LL | fn f1_2(...) {}
-   |         ^^^^
+   |         ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
    |
 LL | fn f1_2(...) {}
-   |         ^^^^
+   |         ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30
    |
 LL | extern "C" fn f2_1(x: isize, ...) {}
-   |                              ^^^^
+   |                              ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
    |
 LL | extern "C" fn f2_2(...) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
    |
 LL | extern "C" fn f2_2(...) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
    |
 LL | extern "C" fn f2_3(..., x: isize) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
    |
 LL | extern "C" fn f2_3(..., x: isize) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:23:26
    |
 LL | extern fn f3_1(x: isize, ...) {}
-   |                          ^^^^
+   |                          ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
    |
 LL | extern fn f3_2(...) {}
-   |                ^^^^
+   |                ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
    |
 LL | extern fn f3_2(...) {}
-   |                ^^^^
+   |                ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
    |
 LL | extern fn f3_3(..., x: isize) {}
-   |                ^^^^
+   |                ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
    |
 LL | extern fn f3_3(..., x: isize) {}
-   |                ^^^^
+   |                ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:35:13
    |
 LL |     fn e_f1(...);
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:37:13
    |
 LL |     fn e_f2(..., x: isize);
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:44:23
    |
 LL |     fn i_f1(x: isize, ...) {}
-   |                       ^^^^
+   |                       ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
    |
 LL |     fn i_f2(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
    |
 LL |     fn i_f2(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:49:28
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |                            ^^^^
+   |                            ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:53:28
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |                            ^^^^
+   |                            ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:60:23
    |
 LL |     fn t_f1(x: isize, ...) {}
-   |                       ^^^^
+   |                       ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:62:23
    |
 LL |     fn t_f2(x: isize, ...);
-   |                       ^^^^
+   |                       ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
    |
 LL |     fn t_f3(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
    |
 LL |     fn t_f3(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
    |
 LL |     fn t_f4(...);
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
    |
 LL |     fn t_f4(...);
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
    |
 LL |     fn t_f5(..., x: isize) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
    |
 LL |     fn t_f5(..., x: isize) {}
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
    |
 LL |     fn t_f6(..., x: isize);
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
    |
 LL |     fn t_f6(..., x: isize);
-   |             ^^^^
+   |             ^^^
 
 error: aborting due to 34 previous errors
 
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
index c00296c..ba9543b 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
@@ -3,7 +3,6 @@
 // where one side is by-ref and the other is by-move.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 struct X {
     x: (),
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index 8a6ea8e..44dbcb9 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:15:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14
    |
 LL |         Some(ref _y @ _z) => {}
    |              ------^^^--
@@ -8,7 +8,7 @@
    |              value borrowed, by `_y`, here
 
 error: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:14
    |
 LL |         Some(_z @ ref _y) => {}
    |              --^^^------
@@ -18,7 +18,7 @@
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:29:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14
    |
 LL |         Some(ref mut _y @ _z) => {}
    |              ----------^^^--
@@ -27,7 +27,7 @@
    |              value borrowed, by `_y`, here
 
 error: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:14
    |
 LL |         Some(_z @ ref mut _y) => {}
    |              --^^^----------
@@ -37,7 +37,7 @@
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:19
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:19
    |
 LL |         Some(_z @ ref _y) => {}
    |              -----^^^^^^
@@ -52,7 +52,7 @@
    |              ^^^
 
 error[E0382]: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:19
    |
 LL |         Some(_z @ ref mut _y) => {}
    |              -----^^^^^^^^^^
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
index 7a2e512..3ab6f40 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
@@ -1,7 +1,6 @@
 // See issue #12534.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {}
 
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
index cfd978e..f25d5a2 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value
-  --> $DIR/bind-by-move-no-subbindings-fun-param.rs:10:12
+  --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:12
    |
 LL | fn f(a @ A(u): A) -> Box<u8> {
    |      ------^-
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
index 10865b9..d014c98 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
@@ -1,7 +1,6 @@
 // Test that moving on both sides of an `@` pattern is not allowed.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U; // Not copy!
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
index d28edd1..5039f58 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:14:13
+  --> $DIR/borrowck-move-and-move.rs:13:13
    |
 LL |     let a @ b = U;
    |         ----^   - move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -8,7 +8,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:16:17
+  --> $DIR/borrowck-move-and-move.rs:15:17
    |
 LL |     let a @ (b, c) = (U, U);
    |         --------^-   ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -17,7 +17,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:18:17
+  --> $DIR/borrowck-move-and-move.rs:17:17
    |
 LL |     let a @ (b, c) = (u(), u());
    |         --------^-   ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -26,7 +26,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:21:16
+  --> $DIR/borrowck-move-and-move.rs:20:16
    |
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -37,7 +37,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:21:29
+  --> $DIR/borrowck-move-and-move.rs:20:29
    |
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -48,7 +48,7 @@
    |                     value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:28:22
+  --> $DIR/borrowck-move-and-move.rs:27:22
    |
 LL |     match [u(), u(), u(), u()] {
    |           -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait
@@ -59,7 +59,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:32:18
+  --> $DIR/borrowck-move-and-move.rs:31:18
    |
 LL |     match [u(), u(), u(), u()] {
    |           -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait
@@ -70,7 +70,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:25:16
+  --> $DIR/borrowck-move-and-move.rs:24:16
    |
 LL |     fn fun(a @ b: U) {}
    |            ----^
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
index 271f4bc..f1ee87b 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
@@ -3,7 +3,6 @@
 // Test `@` patterns combined with `box` patterns.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 #![feature(box_patterns)]
 
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
index f1680e9..236710e 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
@@ -1,7 +1,6 @@
 // Test `@` patterns combined with `box` patterns.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 #![feature(box_patterns)]
 
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
index 4488836..d9a8bbf 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-at-and-box.rs:37:9
+  --> $DIR/borrowck-pat-at-and-box.rs:36:9
    |
 LL |     let ref a @ box b = Box::new(NC);
    |         -----^^^^^^^-
@@ -8,7 +8,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:39:9
+  --> $DIR/borrowck-pat-at-and-box.rs:38:9
    |
 LL |     let ref a @ box ref mut b = Box::new(nc());
    |         -----^^^^^^^---------
@@ -17,7 +17,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:41:9
+  --> $DIR/borrowck-pat-at-and-box.rs:40:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
@@ -26,7 +26,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:43:9
+  --> $DIR/borrowck-pat-at-and-box.rs:42:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
@@ -35,7 +35,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:46:9
+  --> $DIR/borrowck-pat-at-and-box.rs:45:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
@@ -44,7 +44,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:52:9
+  --> $DIR/borrowck-pat-at-and-box.rs:51:9
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
    |         ---------^^^^^^^-----
@@ -53,7 +53,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:66:9
+  --> $DIR/borrowck-pat-at-and-box.rs:65:9
    |
 LL |         ref mut a @ box ref b => {
    |         ---------^^^^^^^-----
@@ -62,7 +62,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:58:11
+  --> $DIR/borrowck-pat-at-and-box.rs:57:11
    |
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
    |           ---------^^^^^^^-----
@@ -71,7 +71,7 @@
    |           mutable borrow, by `a`, occurs here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:21:18
+  --> $DIR/borrowck-pat-at-and-box.rs:20:18
    |
 LL |     let a @ box &b = Box::new(&C);
    |         ---------^   ------------ move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait
@@ -80,7 +80,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:24:17
+  --> $DIR/borrowck-pat-at-and-box.rs:23:17
    |
 LL |     let a @ box b = Box::new(C);
    |         --------^   ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait
@@ -89,7 +89,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:34:17
+  --> $DIR/borrowck-pat-at-and-box.rs:33:17
    |
 LL |     match Box::new(C) {
    |           ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait
@@ -100,7 +100,7 @@
    |         value moved here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:46:21
+  --> $DIR/borrowck-pat-at-and-box.rs:45:21
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         ------------^^^^^^^^^
@@ -112,7 +112,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:52:25
+  --> $DIR/borrowck-pat-at-and-box.rs:51:25
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
    |         ----------------^^^^^
@@ -124,7 +124,7 @@
    |     -- mutable borrow later used here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:66:25
+  --> $DIR/borrowck-pat-at-and-box.rs:65:25
    |
 LL |         ref mut a @ box ref b => {
    |         ----------------^^^^^
@@ -136,7 +136,7 @@
    |             -- mutable borrow later used here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:27:20
+  --> $DIR/borrowck-pat-at-and-box.rs:26:20
    |
 LL |     fn f1(a @ box &b: Box<&C>) {}
    |           ---------^
@@ -146,7 +146,7 @@
    |           move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:30:19
+  --> $DIR/borrowck-pat-at-and-box.rs:29:19
    |
 LL |     fn f2(a @ box b: Box<C>) {}
    |           --------^
@@ -156,7 +156,7 @@
    |           move occurs because value has type `Box<C>`, which does not implement the `Copy` trait
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:58:27
+  --> $DIR/borrowck-pat-at-and-box.rs:57:27
    |
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
    |           ----------------^^^^^
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
index 993954b..a22d277 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
@@ -2,7 +2,6 @@
 // Currently this logic exists in THIR match checking as opposed to borrowck.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
index dacf23f..0e09d47 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -1,5 +1,5 @@
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:9:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:8:9
    |
 LL |     let a @ ref b = U;
    |         -^^^-----
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
index 7d9618c..3e5a543 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
@@ -1,7 +1,6 @@
 // Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index 86e09e5..282031a 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -1,5 +1,5 @@
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:28:9
    |
 LL |     let a @ ref b = U;
    |         -^^^-----
@@ -9,7 +9,7 @@
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         -^^^^^^^^^^^^---------^^^^^^-----^
@@ -20,7 +20,7 @@
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:14
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |              -----^^^---------
@@ -30,7 +30,7 @@
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |                                 -^^^-----
@@ -40,7 +40,7 @@
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:9
    |
 LL |     let a @ [ref mut b, ref c] = [U, U];
    |         -^^^^---------^^-----^
@@ -51,7 +51,7 @@
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:9
    |
 LL |     let a @ ref b = u();
    |         -^^^-----
@@ -61,7 +61,7 @@
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         -^^^^^^^^^^^^---------^^^^^^-----^
@@ -72,7 +72,7 @@
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:14
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |              -----^^^---------
@@ -82,7 +82,7 @@
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |                                 -^^^-----
@@ -92,7 +92,7 @@
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:9
    |
 LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         -^^^^---------^^-----^
@@ -103,7 +103,7 @@
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
    |
 LL |         a @ Some(ref b) => {}
    |         -^^^^^^^^-----^
@@ -113,7 +113,7 @@
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:9
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
@@ -124,7 +124,7 @@
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:19
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   -----^^^---------
@@ -134,7 +134,7 @@
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      -^^^-----
@@ -144,7 +144,7 @@
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:9
    |
 LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         -----^^^^^^^^^-----^^---------^^
@@ -155,7 +155,7 @@
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:9
    |
 LL |         a @ Some(ref b) => {}
    |         -^^^^^^^^-----^
@@ -165,7 +165,7 @@
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:9
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
@@ -176,7 +176,7 @@
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:19
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   -----^^^---------
@@ -186,7 +186,7 @@
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      -^^^-----
@@ -196,7 +196,7 @@
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:9
    |
 LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         -----^^^^^^^^^-----^^---------^^
@@ -207,7 +207,7 @@
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:11
    |
 LL |     fn f1(a @ ref b: U) {}
    |           -^^^-----
@@ -217,7 +217,7 @@
    |           move occurs because `a` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:11
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           -----^^^^^^^^-----^^^^^^^^^^-----^
@@ -228,7 +228,7 @@
    |           move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:20
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                    -^^^-----
@@ -238,7 +238,7 @@
    |                    move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                               -----^^^-----
@@ -248,7 +248,7 @@
    |                               move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:11
    |
 LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
    |           -^^^^---------^^-----^
@@ -259,7 +259,7 @@
    |           move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:22
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |              --------^^^^^^^^^
@@ -270,7 +270,7 @@
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         ------------------------^^^^^^^^^-   ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -279,7 +279,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:37
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:37
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |                                 ----^^^^^
@@ -290,7 +290,7 @@
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:25
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:25
    |
 LL |     let a @ [ref mut b, ref c] = [U, U];
    |         ----------------^^^^^-   ------ move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait
@@ -299,7 +299,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:13
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:13
    |
 LL |     let a @ ref b = u();
    |         ----^^^^^   --- move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -308,7 +308,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:22
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:22
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |              --------^^^^^^^^^
@@ -319,7 +319,7 @@
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         ------------------------^^^^^^^^^-   ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -328,7 +328,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:37
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:37
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |                                 ----^^^^^
@@ -339,7 +339,7 @@
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:25
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:25
    |
 LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         ----------------^^^^^-   ---------- move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait
@@ -348,7 +348,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:27
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:27
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   --------^^^^^^^^^
@@ -363,7 +363,7 @@
    |                   ^^^
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38
    |
 LL |     match Some((U, U)) {
    |           ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
@@ -374,7 +374,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:42
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:42
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      ----^^^^^
@@ -389,7 +389,7 @@
    |                                      ^^^
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:30
    |
 LL |     match Some([U, U]) {
    |           ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
@@ -400,7 +400,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:18
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:18
    |
 LL |     match Some(u()) {
    |           --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
@@ -411,7 +411,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:27
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:27
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   --------^^^^^^^^^
@@ -426,7 +426,7 @@
    |                   ^^^
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38
    |
 LL |     match Some((u(), u())) {
    |           ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
@@ -437,7 +437,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:42
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:42
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      ----^^^^^
@@ -452,7 +452,7 @@
    |                                      ^^^
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:30
    |
 LL |     match Some([u(), u()]) {
    |           ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
@@ -463,7 +463,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:15
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:15
    |
 LL |     fn f1(a @ ref b: U) {}
    |           ----^^^^^
@@ -473,7 +473,7 @@
    |           move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:24
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:24
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                    ----^^^^^
@@ -484,7 +484,7 @@
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           --------------------^^^^^^^^^^^^^-
@@ -494,7 +494,7 @@
    |           move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:39
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:39
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                               --------^^^^^
@@ -505,7 +505,7 @@
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:27
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:27
    |
 LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
    |           ----------------^^^^^-
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
index b7c8c87..42c3290 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
@@ -1,7 +1,6 @@
 // Test that `ref mut? @ pat_with_by_move_bindings` is prevented.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
index e5419ef..a275705 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:23:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:22:9
    |
 LL |     let ref a @ b = U;
    |         -----^^^-
@@ -8,7 +8,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:25:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
@@ -18,7 +18,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:25:18
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:24:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                  -----^^^-----
@@ -27,7 +27,7 @@
    |                  value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:25:33
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:24:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                                 -----^^^-
@@ -36,7 +36,7 @@
    |                                 value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:29:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:28:9
    |
 LL |     let ref mut a @ [b, mut c] = [U, U];
    |         ---------^^^^-^^-----^
@@ -46,7 +46,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:31:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
    |
 LL |     let ref a @ b = u();
    |         -----^^^-
@@ -55,7 +55,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:32:9
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
@@ -65,7 +65,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:33:18
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:32:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                  -----^^^-----
@@ -74,7 +74,7 @@
    |                  value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:33:33
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:32:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                                 -----^^^-
@@ -83,7 +83,7 @@
    |                                 value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:37:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
    |
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
    |         ---------^^^^-^^-----^
@@ -93,7 +93,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:41:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:40:9
    |
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
@@ -102,7 +102,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:46:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:45:9
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
@@ -112,7 +112,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:46:23
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:45:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
@@ -121,7 +121,7 @@
    |                       value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:46:38
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:45:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
@@ -130,7 +130,7 @@
    |                                      value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:53:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
    |
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
@@ -140,7 +140,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:58:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:57:9
    |
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
@@ -149,7 +149,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:63:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:62:9
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
@@ -159,7 +159,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:63:23
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:62:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
@@ -168,7 +168,7 @@
    |                       value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:63:38
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:62:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
@@ -177,7 +177,7 @@
    |                                      value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:70:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
    |
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
@@ -187,7 +187,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:13:11
    |
 LL |     fn f1(ref a @ b: U) {}
    |           -----^^^-
@@ -196,7 +196,7 @@
    |           value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:16:11
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:15:11
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |           -----^^^^^^^^^^^^-----^^^^^^^^^^-^
@@ -206,7 +206,7 @@
    |           value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:16:20
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:15:20
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                    -----^^^-----
@@ -215,7 +215,7 @@
    |                    value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:16:35
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:15:35
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                                   -----^^^-
@@ -224,7 +224,7 @@
    |                                   value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:19:11
    |
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
    |           ---------^^^^-^^-----^
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
index 2b5e339..f67cd45 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
@@ -1,5 +1,4 @@
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 enum Option<T> {
     None,
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index 695da96..e6231dd 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -1,5 +1,5 @@
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:9
    |
 LL |         ref mut z @ &mut Some(ref a) => {
    |         ---------^^^^^^^^^^^^^-----^
@@ -8,7 +8,7 @@
    |         mutable borrow, by `z`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:9
    |
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |         ---------^^^^-----------------^
@@ -18,7 +18,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:22
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:22
    |
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |                      -----^^^---------
@@ -27,7 +27,7 @@
    |                      immutable borrow, by `b`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:38:9
    |
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
@@ -36,7 +36,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:40:9
    |
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
@@ -45,7 +45,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:42:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -55,7 +55,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:44:9
    |
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
@@ -65,7 +65,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:9
    |
 LL |     let ref mut a @ ref b = u();
    |         ---------^^^-----
@@ -74,7 +74,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:9
    |
 LL |     let ref a @ ref mut b = u();
    |         -----^^^---------
@@ -83,7 +83,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:59:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:58:9
    |
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
@@ -92,7 +92,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:63:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:62:9
    |
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
@@ -101,7 +101,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |         ---------^^^^^^-----^
@@ -110,7 +110,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |                                 ---------^^^^^^^-----^
@@ -119,7 +119,7 @@
    |                                 mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |         -----^^^^^^---------^
@@ -128,7 +128,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |                                 -----^^^^^^^---------^
@@ -137,7 +137,7 @@
    |                                 immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |         -----^^^^^^---------^
@@ -146,7 +146,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |                                 -----^^^^^^^---------^
@@ -155,7 +155,7 @@
    |                                 immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |         ---------^^^^^^-----^
@@ -164,7 +164,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |                                 ---------^^^^^^^-----^
@@ -173,7 +173,7 @@
    |                                 mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |         -----^^^^^^---------^
@@ -182,7 +182,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                 -----^^^^^^^---------^
@@ -191,7 +191,7 @@
    |                                 immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |         ---------^^^^^^-----^
@@ -200,7 +200,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                 ---------^^^^^^^-----^
@@ -209,7 +209,7 @@
    |                                 mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:118:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -219,7 +219,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -229,7 +229,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -239,7 +239,7 @@
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:136:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:135:9
    |
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
@@ -249,7 +249,7 @@
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:25:11
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
    |
 LL |     fn f1(ref a @ ref mut b: U) {}
    |           -----^^^---------
@@ -258,7 +258,7 @@
    |           immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:27:11
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
    |
 LL |     fn f2(ref mut a @ ref b: U) {}
    |           ---------^^^-----
@@ -267,7 +267,7 @@
    |           mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:29:11
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:11
    |
 LL |     fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
    |           -----^^^^^^^^^^^----------------^^^^^^^^
@@ -276,7 +276,7 @@
    |           immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:22
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:22
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                      -----^^^-------------
@@ -286,7 +286,7 @@
    |                      immutable borrow, by `a`, occurs here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:30
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:30
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                              ---------^^^-
@@ -295,7 +295,7 @@
    |                              value borrowed, by `b`, here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:31
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:31
    |
 LL |         ref mut z @ &mut Some(ref a) => {
    |         ----------------------^^^^^-
@@ -307,7 +307,7 @@
    |             ---------- mutable borrow later used here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:21
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:21
    |
 LL |     let ref mut a @ ref b = u();
    |         ------------^^^^^
@@ -319,7 +319,7 @@
    |     -------- mutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:17
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:17
    |
 LL |     let ref a @ ref mut b = u();
    |         --------^^^^^^^^^
@@ -331,7 +331,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:20
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:20
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |         -----------^^^^^^^^^-
@@ -343,7 +343,7 @@
    |                  - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:45
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:45
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |                                 ------------^^^^^^^^^-
@@ -355,7 +355,7 @@
    |                  - immutable borrow later used here
 
 error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:61
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:61
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |                                                             ^^^^^^ cannot assign
@@ -363,7 +363,7 @@
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
 error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:61
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:61
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |                                                             ^^^^^^^^^^^ cannot assign
@@ -371,7 +371,7 @@
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
 error[E0507]: cannot move out of `b` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                                                  ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
@@ -379,7 +379,7 @@
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0507]: cannot move out of `b` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                                                  ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
@@ -387,7 +387,7 @@
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0507]: cannot move out of `a` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                                                  ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -395,7 +395,7 @@
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0507]: cannot move out of `a` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                                                  ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -403,7 +403,7 @@
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:18
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:18
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         ---------^^^^^^^^^------------
@@ -415,7 +415,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:29
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:29
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         --------------------^^^^^^^^^-
@@ -427,7 +427,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:18
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:18
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         ---------^^^^^^^^^------------
@@ -439,7 +439,7 @@
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:29
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:29
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         --------------------^^^^^^^^^-
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
index a208d00..8faaa1c 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
@@ -1,7 +1,6 @@
 // Test that `ref mut x @ ref mut y` and varieties of that are not allowed.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index 1cd3e26..2e0f5fc 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -1,5 +1,5 @@
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:28:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:27:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -8,7 +8,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:32:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:31:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -17,7 +17,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:35:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:34:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -26,7 +26,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:38:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:37:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -35,7 +35,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:42:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:41:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -44,7 +44,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:46:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:45:9
    |
 LL |       let ref mut a @ (
    |           ^--------
@@ -66,7 +66,7 @@
    | |_____^
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:56:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:55:9
    |
 LL |       let ref mut a @ (
    |           ^--------
@@ -88,7 +88,7 @@
    | |_________^
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:66:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:65:9
    |
 LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         -^^^^---------^^---------^
@@ -99,7 +99,7 @@
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:69:9
    |
 LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         -^^^^-^^^-^^-^^
@@ -111,7 +111,7 @@
    |         move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:73:9
    |
 LL |     let a @ &mut ref mut b = &mut U;
    |         -^^^^^^^^---------
@@ -121,7 +121,7 @@
    |         move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
    |
 LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         -^^^^^^^^^---------^^---------^
@@ -132,7 +132,7 @@
    |         move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:81:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -141,7 +141,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:81:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -150,7 +150,7 @@
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:88:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:87:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -159,7 +159,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:88:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:87:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -168,7 +168,7 @@
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -177,7 +177,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -186,7 +186,7 @@
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -195,7 +195,7 @@
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -204,7 +204,7 @@
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:11:11
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
    |
 LL |     fn f1(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
@@ -213,7 +213,7 @@
    |           first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:13:11
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:12:11
    |
 LL |     fn f2(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
@@ -222,7 +222,7 @@
    |           first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:16:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:15:9
    |
 LL |           ref mut a @ [
    |           ^--------
@@ -240,7 +240,7 @@
    | |_________^
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:24:22
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:23:22
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                      ---------^^^-------------
@@ -250,7 +250,7 @@
    |                      first mutable borrow, by `a`, occurs here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:24:34
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:23:34
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                                  ---------^^^-
@@ -259,7 +259,7 @@
    |                                  value borrowed, by `b`, here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:28:21
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:27:21
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ------------^^^^^^^^^
@@ -271,7 +271,7 @@
    |          - first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:38:21
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:37:21
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ------------^^^^^^^^^
@@ -283,7 +283,7 @@
    |     ------ first borrow later used here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:66:25
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:65:25
    |
 LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         ----------------^^^^^^^^^-   ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -292,7 +292,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:70:21
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:69:21
    |
 LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         ------------^--   -------- move occurs because value has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait
@@ -301,7 +301,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:74:18
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:73:18
    |
 LL |     let a @ &mut ref mut b = &mut U;
    |         ---------^^^^^^^^^   ------ move occurs because value has type `&mut U`, which does not implement the `Copy` trait
@@ -310,7 +310,7 @@
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:77:30
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:76:30
    |
 LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         ---------------------^^^^^^^^^-   ----------- move occurs because value has type `&mut (U, U)`, which does not implement the `Copy` trait
@@ -319,7 +319,7 @@
    |         value moved here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:24
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------------^^^^^^^^^-
@@ -331,7 +331,7 @@
    |             ----------- first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:53
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ----------------^^^^^^^^^-
@@ -343,7 +343,7 @@
    |             ----------- first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:24
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------------^^^^^^^^^-
@@ -355,7 +355,7 @@
    |                  - first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:53
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ----------------^^^^^^^^^-
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
index 821d4b4..3954d17 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
@@ -1,7 +1,6 @@
 // Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 #[derive(Copy, Clone)]
 struct C;
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
index 7e89008..cc2786a 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value
-  --> $DIR/copy-and-move-mixed.rs:12:19
+  --> $DIR/copy-and-move-mixed.rs:11:19
    |
 LL |     let a @ NC(b, c) = NC(C, C);
    |         ----------^-   -------- move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
@@ -8,7 +8,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/copy-and-move-mixed.rs:15:19
+  --> $DIR/copy-and-move-mixed.rs:14:19
    |
 LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
    |         ----------^^^^^^^^^^^^-   --------------- move occurs because value has type `NC<C, NC<C, C>>`, which does not implement the `Copy` trait
@@ -17,7 +17,7 @@
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/copy-and-move-mixed.rs:15:29
+  --> $DIR/copy-and-move-mixed.rs:14:29
    |
 LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
    |                   ----------^-
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
index a454972..276088b 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
@@ -8,7 +8,6 @@
 // this would create problems for the generalization aforementioned.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct NotCopy;
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index a63a5a1..11d5e24 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:28:9
+  --> $DIR/default-binding-modes-both-sides-independent.rs:27:9
    |
 LL |     let ref a @ b = NotCopy;
    |         -----^^^-
@@ -8,7 +8,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:31:9
+  --> $DIR/default-binding-modes-both-sides-independent.rs:30:9
    |
 LL |     let ref mut a @ b = NotCopy;
    |         ---------^^^-
@@ -17,7 +17,7 @@
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:36:12
+  --> $DIR/default-binding-modes-both-sides-independent.rs:35:12
    |
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |            -----^^^-
@@ -26,7 +26,7 @@
    |            value borrowed, by `a`, here
 
 error: borrow of moved value
-  --> $DIR/default-binding-modes-both-sides-independent.rs:36:29
+  --> $DIR/default-binding-modes-both-sides-independent.rs:35:29
    |
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |                             -^^^-----
@@ -36,7 +36,7 @@
    |                             move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:44:9
+  --> $DIR/default-binding-modes-both-sides-independent.rs:43:9
    |
 LL |         ref a @ b => {
    |         -----^^^-
@@ -45,7 +45,7 @@
    |         value borrowed, by `a`, here
 
 error[E0505]: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:31:21
+  --> $DIR/default-binding-modes-both-sides-independent.rs:30:21
    |
 LL |     let ref mut a @ b = NotCopy;
    |         ------------^
diff --git a/src/test/ui/pattern/issue-66501.rs b/src/test/ui/pattern/issue-66501.rs
new file mode 100644
index 0000000..ffcfd4a
--- /dev/null
+++ b/src/test/ui/pattern/issue-66501.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![allow(unreachable_patterns)]
+
+fn main() {
+    const CONST: &[Option<()>; 1] = &[Some(())];
+    match &[Some(())] {
+        &[None] => {}
+        CONST => {}
+        &[Some(())] => {}
+    }
+}
diff --git a/src/test/ui/pattern/issue-72565.rs b/src/test/ui/pattern/issue-72565.rs
new file mode 100644
index 0000000..1e262fd
--- /dev/null
+++ b/src/test/ui/pattern/issue-72565.rs
@@ -0,0 +1,8 @@
+const F: &'static dyn PartialEq<u32> = &7u32;
+
+fn main() {
+    let a: &dyn PartialEq<u32> = &7u32;
+    match a {
+        F => panic!(), //~ ERROR: `&dyn PartialEq<u32>` cannot be used in patterns
+    }
+}
diff --git a/src/test/ui/pattern/issue-72565.stderr b/src/test/ui/pattern/issue-72565.stderr
new file mode 100644
index 0000000..2f82616
--- /dev/null
+++ b/src/test/ui/pattern/issue-72565.stderr
@@ -0,0 +1,8 @@
+error: `&dyn PartialEq<u32>` cannot be used in patterns
+  --> $DIR/issue-72565.rs:6:9
+   |
+LL |         F => panic!(),
+   |         ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
index d2d4e61..5445696 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(move_ref_pattern)]
-
 fn main() {}
 
 struct U;
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
index 3ee008f..9c320ed 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {}
 
 struct U;
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index d718ee2..285c203 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -1,5 +1,5 @@
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:10:24
+  --> $DIR/borrowck-move-ref-pattern.rs:8:24
    |
 LL |     let hold_all = &arr;
    |                    ---- borrow of `arr` occurs here
@@ -10,7 +10,7 @@
    |          -------- borrow later used here
 
 error[E0384]: cannot assign twice to immutable variable `_x1`
-  --> $DIR/borrowck-move-ref-pattern.rs:11:5
+  --> $DIR/borrowck-move-ref-pattern.rs:9:5
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                        ---
@@ -21,7 +21,7 @@
    |     ^^^^^^^ cannot assign twice to immutable variable
 
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:13:10
+  --> $DIR/borrowck-move-ref-pattern.rs:11:10
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |          ------------ borrow of `arr[..]` occurs here
@@ -32,7 +32,7 @@
    |          -------- borrow later used here
 
 error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-move-ref-pattern.rs:15:16
+  --> $DIR/borrowck-move-ref-pattern.rs:13:16
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                             ---------------- immutable borrow occurs here
@@ -44,7 +44,7 @@
    |          ------- immutable borrow later used here
 
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:15:29
+  --> $DIR/borrowck-move-ref-pattern.rs:13:29
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                             ---------------- borrow of `arr[..]` occurs here
@@ -56,7 +56,7 @@
    |          ------- borrow later used here
 
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:15:34
+  --> $DIR/borrowck-move-ref-pattern.rs:13:34
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                             ---------------- borrow of `arr[..]` occurs here
@@ -68,7 +68,7 @@
    |          ------- borrow later used here
 
 error[E0384]: cannot assign twice to immutable variable `_x1`
-  --> $DIR/borrowck-move-ref-pattern.rs:25:5
+  --> $DIR/borrowck-move-ref-pattern.rs:23:5
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |                   ---
@@ -79,7 +79,7 @@
    |     ^^^^^^^ cannot assign twice to immutable variable
 
 error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-move-ref-pattern.rs:26:20
+  --> $DIR/borrowck-move-ref-pattern.rs:24:20
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |          ------- immutable borrow occurs here
@@ -91,7 +91,7 @@
    |     -------- immutable borrow later used here
 
 error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-move-ref-pattern.rs:27:10
+  --> $DIR/borrowck-move-ref-pattern.rs:25:10
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |          ------- immutable borrow occurs here
@@ -102,7 +102,7 @@
    |     -------- immutable borrow later used here
 
 error[E0594]: cannot assign to `*_x0` which is behind a `&` reference
-  --> $DIR/borrowck-move-ref-pattern.rs:28:5
+  --> $DIR/borrowck-move-ref-pattern.rs:26:5
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |          ------- help: consider changing this to be a mutable reference: `ref mut _x0`
@@ -111,7 +111,7 @@
    |     ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written
 
 error[E0594]: cannot assign to `*_x2` which is behind a `&` reference
-  --> $DIR/borrowck-move-ref-pattern.rs:29:5
+  --> $DIR/borrowck-move-ref-pattern.rs:27:5
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |                        ------- help: consider changing this to be a mutable reference: `ref mut _x2`
@@ -120,7 +120,7 @@
    |     ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written
 
 error[E0382]: use of moved value: `tup.1`
-  --> $DIR/borrowck-move-ref-pattern.rs:30:10
+  --> $DIR/borrowck-move-ref-pattern.rs:28:10
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |                   --- value moved here
@@ -131,7 +131,7 @@
    = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value: `tup.1`
-  --> $DIR/borrowck-move-ref-pattern.rs:31:20
+  --> $DIR/borrowck-move-ref-pattern.rs:29:20
    |
 LL |     drop(tup.1);
    |          ----- value moved here
@@ -141,7 +141,7 @@
    = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
 
 error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-move-ref-pattern.rs:33:20
+  --> $DIR/borrowck-move-ref-pattern.rs:31:20
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- mutable borrow occurs here
@@ -152,7 +152,7 @@
    |          --- mutable borrow later used here
 
 error[E0499]: cannot borrow `tup.3` as mutable more than once at a time
-  --> $DIR/borrowck-move-ref-pattern.rs:34:20
+  --> $DIR/borrowck-move-ref-pattern.rs:32:20
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- first mutable borrow occurs here
@@ -164,7 +164,7 @@
    |          --- first borrow later used here
 
 error[E0499]: cannot borrow `tup.3` as mutable more than once at a time
-  --> $DIR/borrowck-move-ref-pattern.rs:35:14
+  --> $DIR/borrowck-move-ref-pattern.rs:33:14
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- first mutable borrow occurs here
@@ -176,7 +176,7 @@
    |          --- first borrow later used here
 
 error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-move-ref-pattern.rs:36:14
+  --> $DIR/borrowck-move-ref-pattern.rs:34:14
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- mutable borrow occurs here
@@ -187,7 +187,7 @@
    |          --- mutable borrow later used here
 
 error[E0382]: use of moved value: `tup`
-  --> $DIR/borrowck-move-ref-pattern.rs:45:14
+  --> $DIR/borrowck-move-ref-pattern.rs:43:14
    |
 LL |     let mut tup = (U, U, U);
    |         ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
index 08fb5cd..18663c3 100644
--- a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
+++ b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
@@ -4,7 +4,6 @@
 
 // check-pass
 
-#![feature(move_ref_pattern)]
 #![feature(bindings_after_at)]
 
 fn main() {
diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs
deleted file mode 100644
index fb92eb1..0000000
--- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-fn main() {
-    #[derive(Clone)]
-    struct X {
-        x: (),
-    }
-    let mut tup = (X { x: () }, X { x: () });
-    match Some(tup.clone()) {
-        Some((y, ref z)) => {}
-        //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-        None => panic!(),
-    }
-
-    let (ref a, b) = tup.clone();
-    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-
-    let (a, mut b) = &tup;
-    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-    //~| ERROR cannot move out of a shared reference
-
-    let (mut a, b) = &mut tup;
-    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-    //~| ERROR cannot move out of a mutable reference
-}
diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr
deleted file mode 100644
index 5335569..0000000
--- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr
+++ /dev/null
@@ -1,66 +0,0 @@
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:8:15
-   |
-LL |         Some((y, ref z)) => {}
-   |               ^  ----- by-ref pattern here
-   |               |
-   |               by-move pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:13:17
-   |
-LL |     let (ref a, b) = tup.clone();
-   |          -----  ^ by-move pattern here
-   |          |
-   |          by-ref pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:16:13
-   |
-LL |     let (a, mut b) = &tup;
-   |          -  ^^^^^ by-move pattern here
-   |          |
-   |          by-ref pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:20:10
-   |
-LL |     let (mut a, b) = &mut tup;
-   |          ^^^^^  - by-ref pattern here
-   |          |
-   |          by-move pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0507]: cannot move out of a shared reference
-  --> $DIR/feature-gate-move_ref_pattern.rs:16:22
-   |
-LL |     let (a, mut b) = &tup;
-   |             -----    ^^^^
-   |             |
-   |             data moved here
-   |             move occurs because `b` has type `X`, which does not implement the `Copy` trait
-
-error[E0507]: cannot move out of a mutable reference
-  --> $DIR/feature-gate-move_ref_pattern.rs:20:22
-   |
-LL |     let (mut a, b) = &mut tup;
-   |          -----       ^^^^^^^^
-   |          |
-   |          data moved here
-   |          move occurs because `a` has type `X`, which does not implement the `Copy` trait
-
-error: aborting due to 6 previous errors
-
-Some errors have detailed explanations: E0507, E0658.
-For more information about an error, try `rustc --explain E0507`.
diff --git a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
index ab7d10d..80effc4 100644
--- a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
+++ b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(move_ref_pattern)]
-
 enum E {
     Foo(String, String, String),
 }
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
index 4c3ca62..ebb1683 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct S; // Not `Copy`.
 
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
index 9ad8487..f19fed0 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
@@ -1,5 +1,5 @@
 error[E0382]: borrow of moved value: `tup0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10
    |
 LL |     let mut tup0 = (S, S);
    |         -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait
@@ -14,7 +14,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10
    |
 LL |     let mut tup1 = (S, S, S);
    |         -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait
@@ -29,7 +29,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:35:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10
    |
 LL |     let tup2 = (S, S);
    |         ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait
@@ -44,7 +44,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:36:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10
    |
 LL |     let tup3 = (S, S, S);
    |         ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait
@@ -59,7 +59,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup4`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10
    |
 LL |     let tup4 = (S, S);
    |         ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait
@@ -74,7 +74,7 @@
    |          ^^^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10
    |
 LL |     let mut arr0 = [S, S, S];
    |         -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait
@@ -89,7 +89,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36
    |
 LL |     let mut arr1 = [S, S, S, S, S];
    |         -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait
@@ -104,7 +104,7 @@
    |                                    ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:45:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10
    |
 LL |     let arr2 = [S, S, S];
    |         ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait
@@ -119,7 +119,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:46:36
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36
    |
 LL |     let arr3 = [S, S, S, S, S];
    |         ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait
@@ -134,7 +134,7 @@
    |                                    ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10
    |
 LL |     let mut tup0: Option<(S, S)> = None;
    |         -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -148,7 +148,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10
    |
 LL |     let mut tup1: Option<(S, S, S)> = None;
    |         -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -163,7 +163,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10
    |
 LL |     let tup2: Option<(S, S)> = None;
    |         ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -178,7 +178,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10
    |
 LL |     let tup3: Option<(S, S, S)> = None;
    |         ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -193,7 +193,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup4`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:21
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21
    |
 LL |     let tup4: Option<(S, S)> = None;
    |         ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -208,7 +208,7 @@
    |                     ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10
    |
 LL |     let mut arr0: Option<[S; 3]> = None;
    |         -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -223,7 +223,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35
    |
 LL |     let mut arr1: Option<[S; 5]> = None;
    |         -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
@@ -238,7 +238,7 @@
    |                                   ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:84:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10
    |
 LL |     let arr2: Option<[S; 3]> = None;
    |         ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -253,7 +253,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:85:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35
    |
 LL |     let arr3: Option<[S; 5]> = None;
    |         ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
@@ -267,7 +267,7 @@
    |                                   ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10
    |
 LL |     let mut tup0: Option<(S, S)> = None;
    |         -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -281,7 +281,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10
    |
 LL |     let mut tup1: Option<(S, S, S)> = None;
    |         -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -296,7 +296,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10
    |
 LL |     let tup2: Option<(S, S)> = None;
    |         ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -311,7 +311,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10
    |
 LL |     let tup3: Option<(S, S, S)> = None;
    |         ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -326,7 +326,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup4`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:21
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21
    |
 LL |     let tup4: Option<(S, S)> = None;
    |         ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -341,7 +341,7 @@
    |                     ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10
    |
 LL |     let mut arr0: Option<[S; 3]> = None;
    |         -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -356,7 +356,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35
    |
 LL |     let mut arr1: Option<[S; 5]> = None;
    |         -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
@@ -371,7 +371,7 @@
    |                                   ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:120:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10
    |
 LL |     let arr2: Option<[S; 3]> = None;
    |         ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -386,7 +386,7 @@
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:121:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35
    |
 LL |     let arr3: Option<[S; 5]> = None;
    |         ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
index e1844d3..583f70f 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct U;
     fn accept_fn_once(_: impl FnOnce()) {}
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
index 7f1c02c..cd619cc 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct U;
     fn accept_fn_once(_: &impl FnOnce()) {}
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
index ca82353..d96e863 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
@@ -1,5 +1,5 @@
 error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
-  --> $DIR/move-ref-patterns-closure-captures.rs:11:14
+  --> $DIR/move-ref-patterns-closure-captures.rs:9:14
    |
 LL |     let c1 = || {
    |              ^^ this closure implements `FnOnce`, not `FnMut`
@@ -11,7 +11,7 @@
    |     ------------- the requirement to implement `FnMut` derives from here
 
 error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
-  --> $DIR/move-ref-patterns-closure-captures.rs:11:14
+  --> $DIR/move-ref-patterns-closure-captures.rs:9:14
    |
 LL |     let c1 = || {
    |              ^^ this closure implements `FnOnce`, not `Fn`
@@ -23,7 +23,7 @@
    |     --------- the requirement to implement `Fn` derives from here
 
 error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
-  --> $DIR/move-ref-patterns-closure-captures.rs:22:14
+  --> $DIR/move-ref-patterns-closure-captures.rs:20:14
    |
 LL |     let c2 = || {
    |              ^^ this closure implements `FnMut`, not `Fn`
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
index 5c51c47..1dd66aa 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct U;
 
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
index f92699f..6952c74 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of a shared reference
-  --> $DIR/move-ref-patterns-default-binding-modes.rs:10:22
+  --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22
    |
 LL |     let (a, mut b) = &p;
    |             -----    ^^
@@ -8,7 +8,7 @@
    |             move occurs because `b` has type `U`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of a mutable reference
-  --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22
+  --> $DIR/move-ref-patterns-default-binding-modes.rs:12:22
    |
 LL |     let (a, mut b) = &mut p;
    |             -----    ^^^^^^
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
index c786953..1d6d9ac 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
@@ -3,8 +3,6 @@
 // This test checks the dynamic semantics and drop order of pattern matching
 // where a product pattern has both a by-move and by-ref binding.
 
-#![feature(move_ref_pattern)]
-
 use std::cell::RefCell;
 use std::rc::Rc;
 
diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.rs b/src/test/ui/pattern/patkind-litrange-no-expr.rs
index 5b3db2e..9464f27 100644
--- a/src/test/ui/pattern/patkind-litrange-no-expr.rs
+++ b/src/test/ui/pattern/patkind-litrange-no-expr.rs
@@ -19,7 +19,7 @@
     Neg = -1,
     Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
                    //~| ERROR arbitrary expressions aren't allowed in patterns
-                   //~| ERROR only char and numeric types are allowed in range patterns
+                   //~| ERROR only `char` and numeric types are allowed in range patterns
 });
 
 fn main() {}
diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.stderr b/src/test/ui/pattern/patkind-litrange-no-expr.stderr
index 70dd1a9..51af167 100644
--- a/src/test/ui/pattern/patkind-litrange-no-expr.stderr
+++ b/src/test/ui/pattern/patkind-litrange-no-expr.stderr
@@ -10,7 +10,7 @@
 LL |     Arith = 1 + 1,
    |             ^^^^^
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/patkind-litrange-no-expr.rs:20:13
    |
 LL |                 $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range
diff --git a/src/test/ui/pattern/pattern-tyvar-2.rs b/src/test/ui/pattern/pattern-tyvar-2.rs
index 532df4f..7647c76 100644
--- a/src/test/ui/pattern/pattern-tyvar-2.rs
+++ b/src/test/ui/pattern/pattern-tyvar-2.rs
@@ -1,6 +1,6 @@
 enum Bar { T1((), Option<Vec<isize>>), T2, }
 
 fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } }
-//~^ ERROR cannot multiply `{integer}` to `Vec<isize>`
+//~^ ERROR cannot multiply `Vec<isize>` by `{integer}`
 
 fn main() { }
diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr
index e205cd9..121817e 100644
--- a/src/test/ui/pattern/pattern-tyvar-2.stderr
+++ b/src/test/ui/pattern/pattern-tyvar-2.stderr
@@ -1,4 +1,4 @@
-error[E0369]: cannot multiply `{integer}` to `Vec<isize>`
+error[E0369]: cannot multiply `Vec<isize>` by `{integer}`
   --> $DIR/pattern-tyvar-2.rs:3:71
    |
 LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } }
diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr
index 266b6e6..6333558 100644
--- a/src/test/ui/polymorphization/const_parameters/closures.stderr
+++ b/src/test/ui/polymorphization/const_parameters/closures.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:19:19
diff --git a/src/test/ui/polymorphization/const_parameters/functions.stderr b/src/test/ui/polymorphization/const_parameters/functions.stderr
index e379e32..c976a5b 100644
--- a/src/test/ui/polymorphization/const_parameters/functions.stderr
+++ b/src/test/ui/polymorphization/const_parameters/functions.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: item has unused generic parameters
   --> $DIR/functions.rs:15:8
diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr
index c59055b..b2b32db 100644
--- a/src/test/ui/polymorphization/generators.stderr
+++ b/src/test/ui/polymorphization/generators.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: item has unused generic parameters
   --> $DIR/generators.rs:36:5
diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs
index 5238894..fba72c1 100644
--- a/src/test/ui/privacy/private-in-public-assoc-ty.rs
+++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs
@@ -21,15 +21,15 @@
     // "Private-in-public in associated types is hard error" in RFC 2145
     // applies only to the aliased types, not bounds.
     pub trait PubTr {
+        type Alias1: PrivTr;
         //~^ WARN private trait `PrivTr` in public interface
         //~| WARN this was previously accepted
-        //~| WARN private type `Priv` in public interface
-        //~| WARN private type `Priv` in public interface
-        //~| WARN this was previously accepted
-        //~| WARN this was previously accepted
-        type Alias1: PrivTr;
         type Alias2: PubTrAux1<Priv> = u8;
+        //~^ WARN private type `Priv` in public interface
+        //~| WARN this was previously accepted
         type Alias3: PubTrAux2<A = Priv> = u8;
+        //~^ WARN private type `Priv` in public interface
+        //~| WARN this was previously accepted
 
         type Alias4 = Priv;
         //~^ ERROR private type `Priv` in public interface
diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr
index acc6e20..ba62a22 100644
--- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr
+++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr
@@ -2,53 +2,35 @@
   --> $DIR/private-in-public-assoc-ty.rs:17:9
    |
 LL |     struct Priv;
-   |     - `Priv` declared as private
+   |     ------------ `Priv` declared as private
 ...
 LL |         type A = Priv;
    |         ^^^^^^^^^^^^^^ can't leak private type
 
 warning: private trait `PrivTr` in public interface (error E0445)
-  --> $DIR/private-in-public-assoc-ty.rs:23:5
+  --> $DIR/private-in-public-assoc-ty.rs:24:9
    |
-LL | /     pub trait PubTr {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |         fn infer_exist() -> Self::Exist;
-LL | |     }
-   | |_____^
+LL |         type Alias1: PrivTr;
+   |         ^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(private_in_public)]` on by default
    = 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 #34537 <https://github.com/rust-lang/rust/issues/34537>
 
 warning: private type `Priv` in public interface (error E0446)
-  --> $DIR/private-in-public-assoc-ty.rs:23:5
+  --> $DIR/private-in-public-assoc-ty.rs:27:9
    |
-LL | /     pub trait PubTr {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |         fn infer_exist() -> Self::Exist;
-LL | |     }
-   | |_____^
+LL |         type Alias2: PubTrAux1<Priv> = u8;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #34537 <https://github.com/rust-lang/rust/issues/34537>
 
 warning: private type `Priv` in public interface (error E0446)
-  --> $DIR/private-in-public-assoc-ty.rs:23:5
+  --> $DIR/private-in-public-assoc-ty.rs:30:9
    |
-LL | /     pub trait PubTr {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |         fn infer_exist() -> Self::Exist;
-LL | |     }
-   | |_____^
+LL |         type Alias3: PubTrAux2<A = Priv> = u8;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #34537 <https://github.com/rust-lang/rust/issues/34537>
@@ -57,7 +39,7 @@
   --> $DIR/private-in-public-assoc-ty.rs:34:9
    |
 LL |     struct Priv;
-   |     - `Priv` declared as private
+   |     ------------ `Priv` declared as private
 ...
 LL |         type Alias4 = Priv;
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -66,7 +48,7 @@
   --> $DIR/private-in-public-assoc-ty.rs:41:9
    |
 LL |     struct Priv;
-   |     - `Priv` declared as private
+   |     ------------ `Priv` declared as private
 ...
 LL |         type Alias1 = Priv;
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -75,7 +57,7 @@
   --> $DIR/private-in-public-assoc-ty.rs:44:9
    |
 LL |     trait PrivTr {}
-   |     - `PrivTr` declared as private
+   |     ------------ `PrivTr` declared as private
 ...
 LL |         type Exist = impl PrivTr;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
diff --git a/src/test/ui/privacy/private-in-public-lint.stderr b/src/test/ui/privacy/private-in-public-lint.stderr
index 377bd58b..dd5f5b6 100644
--- a/src/test/ui/privacy/private-in-public-lint.stderr
+++ b/src/test/ui/privacy/private-in-public-lint.stderr
@@ -2,7 +2,7 @@
   --> $DIR/private-in-public-lint.rs:6:9
    |
 LL |     struct Priv;
-   |     - `m1::Priv` declared as private
+   |     ------------ `m1::Priv` declared as private
 ...
 LL |         pub fn f() -> Priv {Priv}
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -11,7 +11,7 @@
   --> $DIR/private-in-public-lint.rs:15:9
    |
 LL |     struct Priv;
-   |     - `m2::Priv` declared as private
+   |     ------------ `m2::Priv` declared as private
 ...
 LL |         pub fn f() -> Priv {Priv}
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/privacy/private-in-public-warn.rs b/src/test/ui/privacy/private-in-public-warn.rs
index 3022b47..1c8706d 100644
--- a/src/test/ui/privacy/private-in-public-warn.rs
+++ b/src/test/ui/privacy/private-in-public-warn.rs
@@ -55,9 +55,9 @@
     pub trait Tr2<T: PrivTr> {} //~ ERROR private trait `traits::PrivTr` in public interface
         //~^ WARNING hard error
     pub trait Tr3 {
+        type Alias: PrivTr;
         //~^ ERROR private trait `traits::PrivTr` in public interface
         //~| WARNING hard error
-        type Alias: PrivTr;
         fn f<T: PrivTr>(arg: T) {} //~ ERROR private trait `traits::PrivTr` in public interface
         //~^ WARNING hard error
     }
diff --git a/src/test/ui/privacy/private-in-public-warn.stderr b/src/test/ui/privacy/private-in-public-warn.stderr
index 36577a6..8240cc3 100644
--- a/src/test/ui/privacy/private-in-public-warn.stderr
+++ b/src/test/ui/privacy/private-in-public-warn.stderr
@@ -43,7 +43,7 @@
   --> $DIR/private-in-public-warn.rs:26:9
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |         type Alias = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -97,7 +97,7 @@
   --> $DIR/private-in-public-warn.rs:41:9
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |         type Alias = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -130,16 +130,10 @@
    = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
 
 error: private trait `traits::PrivTr` in public interface (error E0445)
-  --> $DIR/private-in-public-warn.rs:57:5
+  --> $DIR/private-in-public-warn.rs:58:9
    |
-LL | /     pub trait Tr3 {
-LL | |
-LL | |
-LL | |         type Alias: PrivTr;
-LL | |         fn f<T: PrivTr>(arg: T) {}
-LL | |
-LL | |     }
-   | |_____^
+LL |         type Alias: PrivTr;
+   |         ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #34537 <https://github.com/rust-lang/rust/issues/34537>
@@ -256,7 +250,7 @@
   --> $DIR/private-in-public-warn.rs:135:9
    |
 LL |     struct Priv;
-   |     - `impls::Priv` declared as private
+   |     ------------ `impls::Priv` declared as private
 ...
 LL |         type Alias = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -274,7 +268,7 @@
   --> $DIR/private-in-public-warn.rs:210:9
    |
 LL |     struct Priv;
-   |     - `aliases_pub::Priv` declared as private
+   |     ------------ `aliases_pub::Priv` declared as private
 ...
 LL |         type Check = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -283,7 +277,7 @@
   --> $DIR/private-in-public-warn.rs:213:9
    |
 LL |     struct Priv;
-   |     - `aliases_pub::Priv` declared as private
+   |     ------------ `aliases_pub::Priv` declared as private
 ...
 LL |         type Check = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -292,7 +286,7 @@
   --> $DIR/private-in-public-warn.rs:216:9
    |
 LL |     struct Priv;
-   |     - `aliases_pub::Priv` declared as private
+   |     ------------ `aliases_pub::Priv` declared as private
 ...
 LL |         type Check = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -301,7 +295,7 @@
   --> $DIR/private-in-public-warn.rs:219:9
    |
 LL |     struct Priv;
-   |     - `aliases_pub::Priv` declared as private
+   |     ------------ `aliases_pub::Priv` declared as private
 ...
 LL |         type Check = Priv;
    |         ^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/privacy/private-in-public.stderr b/src/test/ui/privacy/private-in-public.stderr
index 2ec5b45..e8bb2cd 100644
--- a/src/test/ui/privacy/private-in-public.stderr
+++ b/src/test/ui/privacy/private-in-public.stderr
@@ -2,7 +2,7 @@
   --> $DIR/private-in-public.rs:13:5
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |     pub const C: Priv = Priv;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -11,7 +11,7 @@
   --> $DIR/private-in-public.rs:14:5
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |     pub static S: Priv = Priv;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -20,7 +20,7 @@
   --> $DIR/private-in-public.rs:15:5
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |     pub fn f1(arg: Priv) {}
    |     ^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -29,7 +29,7 @@
   --> $DIR/private-in-public.rs:16:5
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |     pub fn f2() -> Priv { panic!() }
    |     ^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -38,7 +38,7 @@
   --> $DIR/private-in-public.rs:17:19
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |     pub struct S1(pub Priv);
    |                   ^^^^^^^^ can't leak private type
@@ -47,7 +47,7 @@
   --> $DIR/private-in-public.rs:18:21
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |     pub struct S2 { pub field: Priv }
    |                     ^^^^^^^^^^^^^^^ can't leak private type
@@ -56,7 +56,7 @@
   --> $DIR/private-in-public.rs:20:9
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |         pub const C: Priv = Priv;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -65,7 +65,7 @@
   --> $DIR/private-in-public.rs:21:9
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |         pub fn f1(arg: Priv) {}
    |         ^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -74,7 +74,7 @@
   --> $DIR/private-in-public.rs:22:9
    |
 LL |     struct Priv;
-   |     - `types::Priv` declared as private
+   |     ------------ `types::Priv` declared as private
 ...
 LL |         pub fn f2() -> Priv { panic!() }
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -83,7 +83,7 @@
   --> $DIR/private-in-public.rs:31:5
    |
 LL |     trait PrivTr {}
-   |     - `traits::PrivTr` declared as private
+   |     ------------ `traits::PrivTr` declared as private
 ...
 LL |     pub enum E<T: PrivTr> { V(T) }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -92,7 +92,7 @@
   --> $DIR/private-in-public.rs:32:5
    |
 LL |     trait PrivTr {}
-   |     - `traits::PrivTr` declared as private
+   |     ------------ `traits::PrivTr` declared as private
 ...
 LL |     pub fn f<T: PrivTr>(arg: T) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -101,7 +101,7 @@
   --> $DIR/private-in-public.rs:33:5
    |
 LL |     trait PrivTr {}
-   |     - `traits::PrivTr` declared as private
+   |     ------------ `traits::PrivTr` declared as private
 ...
 LL |     pub struct S1<T: PrivTr>(T);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -110,7 +110,7 @@
   --> $DIR/private-in-public.rs:34:5
    |
 LL |       trait PrivTr {}
-   |       - `traits::PrivTr` declared as private
+   |       ------------ `traits::PrivTr` declared as private
 ...
 LL | /     impl<T: PrivTr> Pub<T> {
 LL | |         pub fn f<U: PrivTr>(arg: U) {}
@@ -121,7 +121,7 @@
   --> $DIR/private-in-public.rs:35:9
    |
 LL |     trait PrivTr {}
-   |     - `traits::PrivTr` declared as private
+   |     ------------ `traits::PrivTr` declared as private
 ...
 LL |         pub fn f<U: PrivTr>(arg: U) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -130,7 +130,7 @@
   --> $DIR/private-in-public.rs:44:5
    |
 LL |     trait PrivTr {}
-   |     - `traits_where::PrivTr` declared as private
+   |     ------------ `traits_where::PrivTr` declared as private
 ...
 LL |     pub enum E<T> where T: PrivTr { V(T) }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -139,7 +139,7 @@
   --> $DIR/private-in-public.rs:46:5
    |
 LL |     trait PrivTr {}
-   |     - `traits_where::PrivTr` declared as private
+   |     ------------ `traits_where::PrivTr` declared as private
 ...
 LL |     pub fn f<T>(arg: T) where T: PrivTr {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -148,7 +148,7 @@
   --> $DIR/private-in-public.rs:48:5
    |
 LL |     trait PrivTr {}
-   |     - `traits_where::PrivTr` declared as private
+   |     ------------ `traits_where::PrivTr` declared as private
 ...
 LL |     pub struct S1<T>(T) where T: PrivTr;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -157,7 +157,7 @@
   --> $DIR/private-in-public.rs:50:5
    |
 LL |       trait PrivTr {}
-   |       - `traits_where::PrivTr` declared as private
+   |       ------------ `traits_where::PrivTr` declared as private
 ...
 LL | /     impl<T> Pub<T> where T: PrivTr {
 LL | |
@@ -170,7 +170,7 @@
   --> $DIR/private-in-public.rs:52:9
    |
 LL |     trait PrivTr {}
-   |     - `traits_where::PrivTr` declared as private
+   |     ------------ `traits_where::PrivTr` declared as private
 ...
 LL |         pub fn f<U>(arg: U) where U: PrivTr {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -179,7 +179,7 @@
   --> $DIR/private-in-public.rs:63:5
    |
 LL |     struct Priv<T = u8>(T);
-   |     - `generics::Priv` declared as private
+   |     ----------------------- `generics::Priv` declared as private
 ...
 LL |     pub fn f1(arg: [Priv; 1]) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -188,7 +188,7 @@
   --> $DIR/private-in-public.rs:64:5
    |
 LL |     struct Priv<T = u8>(T);
-   |     - `generics::Priv` declared as private
+   |     ----------------------- `generics::Priv` declared as private
 ...
 LL |     pub fn f2(arg: Pub<Priv>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -197,7 +197,7 @@
   --> $DIR/private-in-public.rs:65:5
    |
 LL |     struct Priv<T = u8>(T);
-   |     - `generics::Priv<generics::Pub>` declared as private
+   |     ----------------------- `generics::Priv<generics::Pub>` declared as private
 ...
 LL |     pub fn f3(arg: Priv<Pub>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -206,7 +206,7 @@
   --> $DIR/private-in-public.rs:80:9
    |
 LL |     struct Priv;
-   |     - `impls::Priv` declared as private
+   |     ------------ `impls::Priv` declared as private
 ...
 LL |         pub fn f(arg: Priv) {}
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -215,7 +215,7 @@
   --> $DIR/private-in-public.rs:104:5
    |
 LL |     trait PrivTr {
-   |     - `aliases_pub::PrivTr` declared as private
+   |     ------------ `aliases_pub::PrivTr` declared as private
 ...
 LL |     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -224,7 +224,7 @@
   --> $DIR/private-in-public.rs:104:5
    |
 LL |     struct Priv;
-   |     - `aliases_pub::Priv` declared as private
+   |     ------------ `aliases_pub::Priv` declared as private
 ...
 LL |     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -233,7 +233,7 @@
   --> $DIR/private-in-public.rs:109:9
    |
 LL |     struct Priv;
-   |     - `aliases_pub::Priv` declared as private
+   |     ------------ `aliases_pub::Priv` declared as private
 ...
 LL |         pub fn f(arg: Priv) {}
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -242,7 +242,7 @@
   --> $DIR/private-in-public.rs:131:5
    |
 LL |     struct Priv1;
-   |     - `Priv1` declared as private
+   |     ------------- `Priv1` declared as private
 ...
 LL |     pub fn f1(arg: PrivUseAlias) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -251,7 +251,7 @@
   --> $DIR/private-in-public.rs:132:5
    |
 LL |     struct Priv2;
-   |     - `Priv2` declared as private
+   |     ------------- `Priv2` declared as private
 ...
 LL |     pub fn f2(arg: PrivAlias) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -260,7 +260,7 @@
   --> $DIR/private-in-public.rs:133:5
    |
 LL |     trait PrivTr {
-   |     - `aliases_priv::PrivTr` declared as private
+   |     ------------ `aliases_priv::PrivTr` declared as private
 ...
 LL |     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
@@ -269,7 +269,7 @@
   --> $DIR/private-in-public.rs:133:5
    |
 LL |     struct Priv;
-   |     - `aliases_priv::Priv` declared as private
+   |     ------------ `aliases_priv::Priv` declared as private
 ...
 LL |     pub fn f3(arg: <Priv as PrivTr>::Assoc) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -278,7 +278,7 @@
   --> $DIR/private-in-public.rs:143:5
    |
 LL |     struct Priv;
-   |     - `aliases_params::Priv` declared as private
+   |     ------------ `aliases_params::Priv` declared as private
 ...
 LL |     pub fn f2(arg: PrivAliasGeneric) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -287,7 +287,7 @@
   --> $DIR/private-in-public.rs:145:5
    |
 LL |     struct Priv;
-   |     - `aliases_params::Priv` declared as private
+   |     ------------ `aliases_params::Priv` declared as private
 ...
 LL |     pub fn f3(arg: Result<u8>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/privacy/private-inferred-type.stderr b/src/test/ui/privacy/private-inferred-type.stderr
index 4a310f7..8c8163d 100644
--- a/src/test/ui/privacy/private-inferred-type.stderr
+++ b/src/test/ui/privacy/private-inferred-type.stderr
@@ -2,7 +2,7 @@
   --> $DIR/private-inferred-type.rs:61:36
    |
 LL |     struct Priv;
-   |     - `Priv` declared as private
+   |     ------------ `Priv` declared as private
 ...
 LL |     impl TraitWithAssocTy for u8 { type AssocTy = Priv; }
    |                                    ^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -11,7 +11,7 @@
   --> $DIR/private-inferred-type.rs:83:9
    |
 LL |     struct S2;
-   |     - `S2` declared as private
+   |     ---------- `S2` declared as private
 ...
 LL |         type Target = S2Alias;
    |         ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
index e485263..f926eee 100644
--- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
+++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
@@ -1,5 +1,5 @@
- // aux-crate:priv:priv_dep=priv_dep.rs
- // aux-build:pub_dep.rs
+// aux-crate:priv:priv_dep=priv_dep.rs
+// aux-build:pub_dep.rs
 #![deny(exported_private_dependencies)]
 
 // This crate is a private dependency
@@ -7,20 +7,20 @@
 // This crate is a public dependency
 extern crate pub_dep;
 
-use priv_dep::{OtherType, OtherTrait};
+use priv_dep::{OtherTrait, OtherType};
 use pub_dep::PubType;
 
 // Type from private dependency used in private
 // type - this is fine
 struct PrivateType {
-    field: OtherType
+    field: OtherType,
 }
 
 pub struct PublicType {
     pub field: OtherType,
     //~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface
-    priv_field: OtherType, // Private field - this is fine
-    pub other_field: PubType // Type from public dependency - this is fine
+    priv_field: OtherType,    // Private field - this is fine
+    pub other_field: PubType, // Type from public dependency - this is fine
 }
 
 impl PublicType {
@@ -33,13 +33,11 @@
 pub trait MyPubTrait {
     type Foo: OtherTrait;
 }
-//~^^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
+//~^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface
 
 pub struct AllowedPrivType {
     #[allow(exported_private_dependencies)]
-    pub allowed: OtherType
+    pub allowed: OtherType,
 }
 
-
-
 fn main() {}
diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
index 3b5b782..e6b4d33 100644
--- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
+++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
@@ -17,12 +17,10 @@
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
-  --> $DIR/pub-priv1.rs:33:1
+  --> $DIR/pub-priv1.rs:34:5
    |
-LL | / pub trait MyPubTrait {
-LL | |     type Foo: OtherTrait;
-LL | | }
-   | |_^
+LL |     type Foo: OtherTrait;
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/privacy/restricted/private-in-public.stderr b/src/test/ui/privacy/restricted/private-in-public.stderr
index 80995ab..c14382c 100644
--- a/src/test/ui/privacy/restricted/private-in-public.stderr
+++ b/src/test/ui/privacy/restricted/private-in-public.stderr
@@ -2,7 +2,7 @@
   --> $DIR/private-in-public.rs:8:9
    |
 LL |     struct Priv;
-   |     - `Priv` declared as private
+   |     ------------ `Priv` declared as private
 ...
 LL |         pub(crate) fn g(_: Priv) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
@@ -11,7 +11,7 @@
   --> $DIR/private-in-public.rs:9:9
    |
 LL |     struct Priv;
-   |     - `Priv` declared as private
+   |     ------------ `Priv` declared as private
 ...
 LL |         crate fn h(_: Priv) {}
    |         ^^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs
new file mode 100644
index 0000000..2d4f601
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Three($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs
new file mode 100644
index 0000000..2d4f601
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Three($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs
new file mode 100644
index 0000000..9ec6aba
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Four($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs
new file mode 100644
index 0000000..9ec6aba
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Four($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
index bc82a2f..652fabf 100644
--- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
+++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
@@ -45,5 +45,33 @@
     other!(Foo);
 }
 
+mod actix_web_test {
+    include!("actix-web/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
+mod actix_web_version_test {
+    include!("actix-web-2.0.0/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
+mod actori_web_test {
+    include!("actori-web/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
+mod actori_web_version_test {
+    include!("actori-web-2.0.0/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
index e83bc9f..c6b18ab 100644
--- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
+++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
@@ -4,3 +4,7 @@
 Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
 Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
 Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:52:21: 52:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:59:21: 59:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:66:21: 66:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:73:21: 73:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
index 3f78dea..a3133a1 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
@@ -9,6 +9,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
index fc821d2..5ef2270 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-1.rs:16:1
+  --> $DIR/invalid-punct-ident-1.rs:19:1
    |
 LL | invalid_punct!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
index 4e89e80..04a0a87 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
@@ -9,6 +9,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
index 8b30eda..4bd7a53 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-2.rs:16:1
+  --> $DIR/invalid-punct-ident-2.rs:19:1
    |
 LL | invalid_ident!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
index 8d8ce8f..aebba34 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
@@ -9,6 +9,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
index d46fab0..072d139 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-3.rs:16:1
+  --> $DIR/invalid-punct-ident-3.rs:19:1
    |
 LL | invalid_raw_ident!();
    | ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/issue-50493.rs b/src/test/ui/proc-macro/issue-50493.rs
index f1934f6..ce0e083 100644
--- a/src/test/ui/proc-macro/issue-50493.rs
+++ b/src/test/ui/proc-macro/issue-50493.rs
@@ -3,8 +3,7 @@
 #[macro_use]
 extern crate issue_50493;
 
-#[derive(Derive)] //~ ERROR field `field` of struct `Restricted` is private
-                  //~| ERROR field `field` of struct `Restricted` is private
+#[derive(Derive)]
 struct Restricted {
     pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules
 }
diff --git a/src/test/ui/proc-macro/issue-50493.stderr b/src/test/ui/proc-macro/issue-50493.stderr
index e378a56..23e103d 100644
--- a/src/test/ui/proc-macro/issue-50493.stderr
+++ b/src/test/ui/proc-macro/issue-50493.stderr
@@ -1,26 +1,9 @@
 error[E0742]: visibilities can only be restricted to ancestor modules
-  --> $DIR/issue-50493.rs:9:12
+  --> $DIR/issue-50493.rs:8:12
    |
 LL |     pub(in restricted) field: usize,
    |            ^^^^^^^^^^
 
-error[E0616]: field `field` of struct `Restricted` is private
-  --> $DIR/issue-50493.rs:6:10
-   |
-LL | #[derive(Derive)]
-   |          ^^^^^^ private field
-   |
-   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
+error: aborting due to previous error
 
-error[E0616]: field `field` of struct `Restricted` is private
-  --> $DIR/issue-50493.rs:6:10
-   |
-LL | #[derive(Derive)]
-   |          ^^^^^^ private field
-   |
-   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0616, E0742.
-For more information about an error, try `rustc --explain E0616`.
+For more information about this error, try `rustc --explain E0742`.
diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.rs b/src/test/ui/proc-macro/issue-75734-pp-paren.rs
new file mode 100644
index 0000000..faa9378
--- /dev/null
+++ b/src/test/ui/proc-macro/issue-75734-pp-paren.rs
@@ -0,0 +1,26 @@
+// Regression test for issue #75734
+// Ensures that we don't lose tokens when pretty-printing would
+// normally insert extra parentheses.
+
+// check-pass
+// aux-build:test-macros.rs
+// compile-flags: -Z span-debug
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+macro_rules! mul_2 {
+    ($val:expr) => {
+        print_bang!($val * 2);
+    };
+}
+
+
+#[print_attr]
+fn main() {
+    &|_: u8| {};
+    mul_2!(1 + 1);
+}
diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
new file mode 100644
index 0000000..b33b85f
--- /dev/null
+++ b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
@@ -0,0 +1,134 @@
+PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | { } ; mul_2 ! (1 + 1) ; }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "fn",
+        span: $DIR/issue-75734-pp-paren.rs:23:1: 23:3 (#0),
+    },
+    Ident {
+        ident: "main",
+        span: $DIR/issue-75734-pp-paren.rs:23:4: 23:8 (#0),
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [],
+        span: $DIR/issue-75734-pp-paren.rs:23:8: 23:10 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Punct {
+                ch: '&',
+                spacing: Joint,
+                span: $DIR/issue-75734-pp-paren.rs:24:5: 24:6 (#0),
+            },
+            Punct {
+                ch: '|',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:6: 24:7 (#0),
+            },
+            Ident {
+                ident: "_",
+                span: $DIR/issue-75734-pp-paren.rs:24:7: 24:8 (#0),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:8: 24:9 (#0),
+            },
+            Ident {
+                ident: "u8",
+                span: $DIR/issue-75734-pp-paren.rs:24:10: 24:12 (#0),
+            },
+            Punct {
+                ch: '|',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:12: 24:13 (#0),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [],
+                span: $DIR/issue-75734-pp-paren.rs:24:14: 24:16 (#0),
+            },
+            Punct {
+                ch: ';',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:16: 24:17 (#0),
+            },
+            Ident {
+                ident: "mul_2",
+                span: $DIR/issue-75734-pp-paren.rs:25:5: 25:10 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:25:10: 25:11 (#0),
+            },
+            Group {
+                delimiter: Parenthesis,
+                stream: TokenStream [
+                    Literal {
+                        kind: Integer,
+                        symbol: "1",
+                        suffix: None,
+                        span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0),
+                    },
+                    Punct {
+                        ch: '+',
+                        spacing: Alone,
+                        span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "1",
+                        suffix: None,
+                        span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0),
+                    },
+                ],
+                span: $DIR/issue-75734-pp-paren.rs:25:11: 25:18 (#0),
+            },
+            Punct {
+                ch: ';',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:25:18: 25:19 (#0),
+            },
+        ],
+        span: $DIR/issue-75734-pp-paren.rs:23:11: 26:2 (#0),
+    },
+]
+PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2
+PRINT-BANG INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: None,
+        stream: TokenStream [
+            Literal {
+                kind: Integer,
+                symbol: "1",
+                suffix: None,
+                span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0),
+            },
+            Punct {
+                ch: '+',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "1",
+                suffix: None,
+                span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0),
+            },
+        ],
+        span: $DIR/issue-75734-pp-paren.rs:17:21: 17:25 (#7),
+    },
+    Punct {
+        ch: '*',
+        spacing: Alone,
+        span: $DIR/issue-75734-pp-paren.rs:17:26: 17:27 (#7),
+    },
+    Literal {
+        kind: Integer,
+        symbol: "2",
+        suffix: None,
+        span: $DIR/issue-75734-pp-paren.rs:17:28: 17:29 (#7),
+    },
+]
diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs
index 90fe109..4a3ba9a 100644
--- a/src/test/ui/proc-macro/load-panic-backtrace.rs
+++ b/src/test/ui/proc-macro/load-panic-backtrace.rs
@@ -10,6 +10,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate test_macros;
diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr
index 63378b5..f825047 100644
--- a/src/test/ui/proc-macro/load-panic-backtrace.stderr
+++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr
@@ -1,6 +1,6 @@
 at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5
 error: proc-macro derive panicked
-  --> $DIR/load-panic-backtrace.rs:17:10
+  --> $DIR/load-panic-backtrace.rs:20:10
    |
 LL | #[derive(Panic)]
    |          ^^^^^
diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.rs b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs
new file mode 100644
index 0000000..2f5af10
--- /dev/null
+++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs
@@ -0,0 +1,26 @@
+// check-pass
+// edition:2018
+// compile-flags: -Z span-debug
+// aux-build:test-macros.rs
+
+// Tests that we properly pass tokens to proc-macro when nested
+// nonterminals are involved.
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+
+macro_rules! wrap {
+    (first, $e:expr) => { wrap!(second, $e + 1) };
+    (second, $e:expr) => { wrap!(third, $e + 2) };
+    (third, $e:expr) => {
+        print_bang!($e + 3);
+    };
+}
+
+fn main() {
+    let _ = wrap!(first, 0);
+}
diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout
new file mode 100644
index 0000000..a3d24dd
--- /dev/null
+++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout
@@ -0,0 +1,60 @@
+PRINT-BANG INPUT (DISPLAY): 0 + 1 + 2 + 3
+PRINT-BANG INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: None,
+        stream: TokenStream [
+            Group {
+                delimiter: None,
+                stream: TokenStream [
+                    Group {
+                        delimiter: None,
+                        stream: TokenStream [
+                            Literal {
+                                kind: Integer,
+                                symbol: "0",
+                                suffix: None,
+                                span: $DIR/nested-nonterminal-tokens.rs:25:26: 25:27 (#0),
+                            },
+                        ],
+                        span: $DIR/nested-nonterminal-tokens.rs:17:41: 17:43 (#4),
+                    },
+                    Punct {
+                        ch: '+',
+                        spacing: Alone,
+                        span: $DIR/nested-nonterminal-tokens.rs:17:44: 17:45 (#4),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "1",
+                        suffix: None,
+                        span: $DIR/nested-nonterminal-tokens.rs:17:46: 17:47 (#4),
+                    },
+                ],
+                span: $DIR/nested-nonterminal-tokens.rs:18:41: 18:43 (#5),
+            },
+            Punct {
+                ch: '+',
+                spacing: Alone,
+                span: $DIR/nested-nonterminal-tokens.rs:18:44: 18:45 (#5),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "2",
+                suffix: None,
+                span: $DIR/nested-nonterminal-tokens.rs:18:46: 18:47 (#5),
+            },
+        ],
+        span: $DIR/nested-nonterminal-tokens.rs:20:21: 20:23 (#6),
+    },
+    Punct {
+        ch: '+',
+        spacing: Alone,
+        span: $DIR/nested-nonterminal-tokens.rs:20:24: 20:25 (#6),
+    },
+    Literal {
+        kind: Integer,
+        symbol: "3",
+        suffix: None,
+        span: $DIR/nested-nonterminal-tokens.rs:20:26: 20:27 (#6),
+    },
+]
diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr
index 70e992a..4064c5b 100644
--- a/src/test/ui/proc-macro/span-preservation.stderr
+++ b/src/test/ui/proc-macro/span-preservation.stderr
@@ -15,7 +15,7 @@
 LL |         Some(x) => { return x },
    |                             ^ expected `usize`, found `isize`
    |
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit
    |
 LL |         Some(x) => { return x.try_into().unwrap() },
    |                             ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs
index d089359..67f888c 100644
--- a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs
+++ b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs
@@ -1,11 +1,11 @@
-#![allow(non_camel_case_types)]  // genus is always capitalized
+#![allow(non_camel_case_types)] // genus is always capitalized
 
 pub(crate) struct Snail;
-//~^ NOTE `Snail` declared as crate-visible
+//~^ NOTE `Snail` declared as private
 
 mod sea {
     pub(super) struct Turtle;
-    //~^ NOTE `Turtle` declared as restricted
+    //~^ NOTE `Turtle` declared as crate-private
 }
 
 struct Tortoise;
@@ -16,11 +16,11 @@
 }
 
 pub type Helix_pomatia = Shell<Snail>;
-//~^ ERROR crate-visible type `Snail` in public interface
-//~| NOTE can't leak crate-visible type
+//~^ ERROR private type `Snail` in public interface
+//~| NOTE can't leak private type
 pub type Dermochelys_coriacea = Shell<sea::Turtle>;
-//~^ ERROR restricted type `Turtle` in public interface
-//~| NOTE can't leak restricted type
+//~^ ERROR crate-private type `Turtle` in public interface
+//~| NOTE can't leak crate-private type
 pub type Testudo_graeca = Shell<Tortoise>;
 //~^ ERROR private type `Tortoise` in public interface
 //~| NOTE can't leak private type
diff --git a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr
index 41b6b09..29d4585 100644
--- a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr
+++ b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr
@@ -1,26 +1,26 @@
-error[E0446]: crate-visible type `Snail` in public interface
+error[E0446]: private type `Snail` in public interface
   --> $DIR/issue-33174-restricted-type-in-public-interface.rs:18:1
    |
 LL | pub(crate) struct Snail;
-   | ---------- `Snail` declared as crate-visible
+   | ------------------------ `Snail` declared as private
 ...
 LL | pub type Helix_pomatia = Shell<Snail>;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-visible type
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
 
-error[E0446]: restricted type `Turtle` in public interface
+error[E0446]: crate-private type `Turtle` in public interface
   --> $DIR/issue-33174-restricted-type-in-public-interface.rs:21:1
    |
 LL |     pub(super) struct Turtle;
-   |     ---------- `Turtle` declared as restricted
+   |     ------------------------- `Turtle` declared as crate-private
 ...
 LL | pub type Dermochelys_coriacea = Shell<sea::Turtle>;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak restricted type
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-private type
 
 error[E0446]: private type `Tortoise` in public interface
   --> $DIR/issue-33174-restricted-type-in-public-interface.rs:24:1
    |
 LL | struct Tortoise;
-   | - `Tortoise` declared as private
+   | ---------------- `Tortoise` declared as private
 ...
 LL | pub type Testudo_graeca = Shell<Tortoise>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
diff --git a/src/test/ui/qualified/qualified-path-params.rs b/src/test/ui/qualified/qualified-path-params.rs
index 65549d9..e8a95a4 100644
--- a/src/test/ui/qualified/qualified-path-params.rs
+++ b/src/test/ui/qualified/qualified-path-params.rs
@@ -18,7 +18,8 @@
 fn main() {
     match 10 {
         <S as Tr>::A::f::<u8> => {}
-    //~^ ERROR expected unit struct, unit variant or constant, found associated function
-        0 ..= <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
+        //~^ ERROR expected unit struct, unit variant or constant, found associated function
+        0 ..= <S as Tr>::A::f::<u8> => {}
+        //~^ ERROR only `char` and numeric types are allowed in range
     }
 }
diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr
index 4214e25..2be2dee 100644
--- a/src/test/ui/qualified/qualified-path-params.stderr
+++ b/src/test/ui/qualified/qualified-path-params.stderr
@@ -4,7 +4,7 @@
 LL |         <S as Tr>::A::f::<u8> => {}
    |         ^^^^^^^^^^^^^^^^^^^^^
 
-error[E0029]: only char and numeric types are allowed in range patterns
+error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/qualified-path-params.rs:22:15
    |
 LL |         0 ..= <S as Tr>::A::f::<u8> => {}
diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr
index f530534..381959b 100644
--- a/src/test/ui/question-mark-type-infer.stderr
+++ b/src/test/ui/question-mark-type-infer.stderr
@@ -1,10 +1,11 @@
-error[E0284]: type annotations needed
+error[E0283]: type annotations needed
   --> $DIR/question-mark-type-infer.rs:12:21
    |
 LL |     l.iter().map(f).collect()?
    |                     ^^^^^^^ cannot infer type
    |
-   = note: cannot satisfy `<_ as Try>::Ok == _`
+   = note: cannot satisfy `_: Try`
+   = note: required by `into_result`
 help: consider specifying the type argument in the method call
    |
 LL |     l.iter().map(f).collect::<B>()?
@@ -12,4 +13,4 @@
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr
index a755732..2cebffe 100644
--- a/src/test/ui/range/range-1.stderr
+++ b/src/test/ui/range/range-1.stderr
@@ -11,6 +11,8 @@
    |              ^^^^^^^^^^^ the trait `Step` is not implemented for `bool`
    |
    = note: required because of the requirements on the impl of `Iterator` for `std::ops::Range<bool>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `std::ops::Range<bool>`
+   = note: required by `into_iter`
 
 error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
   --> $DIR/range-1.rs:14:17
diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.rs b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.rs
index 26cb40b..575dfaf 100644
--- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.rs
+++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.rs
@@ -3,7 +3,7 @@
 
 trait Foo<'a> {
     type Value: 'a;
-    fn dummy(&'a self) { }
+    fn dummy(&'a self) {}
 }
 
 impl<'a> Foo<'a> for &'a i16 {
@@ -12,13 +12,13 @@
 }
 
 impl<'a> Foo<'static> for &'a i32 {
-    //~^ ERROR cannot infer
     type Value = &'a i32;
+    //~^ ERROR the type `&'a i32` does not fulfill the required lifetime
 }
 
-impl<'a,'b> Foo<'b> for &'a i64 {
-    //~^ ERROR cannot infer
+impl<'a, 'b> Foo<'b> for &'a i64 {
     type Value = &'a i32;
+    //~^ ERROR the type `&'a i32` does not fulfill the required lifetime
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
index c134b3b..03da33a 100644
--- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
@@ -1,57 +1,23 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
+error[E0477]: the type `&'a i32` does not fulfill the required lifetime
+  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:15:5
    |
-LL | impl<'a> Foo<'static> for &'a i32 {
-   |          ^^^^^^^^^^^^
+LL |     type Value = &'a i32;
+   |     ^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 14:6...
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:6
-   |
-LL | impl<'a> Foo<'static> for &'a i32 {
-   |      ^^
-note: ...so that the types are compatible
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
-   |
-LL | impl<'a> Foo<'static> for &'a i32 {
-   |          ^^^^^^^^^^^^
-   = note: expected `Foo<'static>`
-              found `Foo<'static>`
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the type `&i32` will meet its required lifetime bounds
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
-   |
-LL | impl<'a> Foo<'static> for &'a i32 {
-   |          ^^^^^^^^^^^^
+   = note: type must satisfy the static lifetime
 
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:13
+error[E0477]: the type `&'a i32` does not fulfill the required lifetime
+  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:20:5
    |
-LL | impl<'a,'b> Foo<'b> for &'a i64 {
-   |             ^^^^^^^
+LL |     type Value = &'a i32;
+   |     ^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 19:6...
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:6
+note: type must outlive the lifetime `'b` as defined on the impl at 19:10
+  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:10
    |
-LL | impl<'a,'b> Foo<'b> for &'a i64 {
-   |      ^^
-note: ...so that the types are compatible
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:13
-   |
-LL | impl<'a,'b> Foo<'b> for &'a i64 {
-   |             ^^^^^^^
-   = note: expected `Foo<'b>`
-              found `Foo<'_>`
-note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9...
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9
-   |
-LL | impl<'a,'b> Foo<'b> for &'a i64 {
-   |         ^^
-note: ...so that the type `&i32` will meet its required lifetime bounds
-  --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:13
-   |
-LL | impl<'a,'b> Foo<'b> for &'a i64 {
-   |             ^^^^^^^
+LL | impl<'a, 'b> Foo<'b> for &'a i64 {
+   |          ^^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.rs b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.rs
index 599cd0b..00100e0 100644
--- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.rs
+++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.rs
@@ -3,12 +3,12 @@
 
 trait Foo {
     type Value: 'static;
-    fn dummy(&self) { }
+    fn dummy(&self) {}
 }
 
 impl<'a> Foo for &'a i32 {
-    //~^ ERROR cannot infer
     type Value = &'a i32;
+    //~^ ERROR the type `&'a i32` does not fulfill the required lifetime
 }
 
 impl<'a> Foo for i32 {
@@ -16,4 +16,4 @@
     type Value = i32;
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
index ac8c55c..d8efeac 100644
--- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
@@ -1,28 +1,11 @@
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
+error[E0477]: the type `&'a i32` does not fulfill the required lifetime
+  --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:10:5
    |
-LL | impl<'a> Foo for &'a i32 {
-   |          ^^^
+LL |     type Value = &'a i32;
+   |     ^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 9:6...
-  --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:6
-   |
-LL | impl<'a> Foo for &'a i32 {
-   |      ^^
-note: ...so that the types are compatible
-  --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
-   |
-LL | impl<'a> Foo for &'a i32 {
-   |          ^^^
-   = note: expected `Foo`
-              found `Foo`
-   = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the type `&i32` will meet its required lifetime bounds
-  --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
-   |
-LL | impl<'a> Foo for &'a i32 {
-   |          ^^^
+   = note: type must satisfy the static lifetime
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/regions/regions-enum-not-wf.rs b/src/test/ui/regions/regions-enum-not-wf.rs
index 781cdb7..6de08f6 100644
--- a/src/test/ui/regions/regions-enum-not-wf.rs
+++ b/src/test/ui/regions/regions-enum-not-wf.rs
@@ -5,17 +5,18 @@
 #![allow(dead_code)]
 
 trait Dummy<'a> {
-  type Out;
+    type Out;
 }
 impl<'a, T> Dummy<'a> for T
-where T: 'a
+where
+    T: 'a,
 {
-  type Out = ();
+    type Out = ();
 }
 type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
 
 enum Ref1<'a, T> {
-    Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough
+    Ref1Variant1(RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
 }
 
 enum Ref2<'a, T> {
@@ -23,18 +24,18 @@
     Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
 }
 
-enum RefOk<'a, T:'a> {
-    RefOkVariant1(&'a T)
+enum RefOk<'a, T: 'a> {
+    RefOkVariant1(&'a T),
 }
 
 // This is now well formed. RFC 2093
 enum RefIndirect<'a, T> {
-    RefIndirectVariant1(isize, RefOk<'a,T>)
+    RefIndirectVariant1(isize, RefOk<'a, T>),
 }
 
-enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309]
-    RefDoubleVariant1(&'a RequireOutlives<'b, T>)
-        //~^ the parameter type `T` may not live long enough [E0309]
+enum RefDouble<'a, 'b, T> {
+    RefDoubleVariant1(&'a RequireOutlives<'b, T>),
+    //~^ the parameter type `T` may not live long enough [E0309]
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/regions/regions-enum-not-wf.stderr b/src/test/ui/regions/regions-enum-not-wf.stderr
index e32a36f..36686ea 100644
--- a/src/test/ui/regions/regions-enum-not-wf.stderr
+++ b/src/test/ui/regions/regions-enum-not-wf.stderr
@@ -1,13 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:18:18
+  --> $DIR/regions-enum-not-wf.rs:19:18
    |
 LL | enum Ref1<'a, T> {
    |               - help: consider adding an explicit lifetime bound...: `T: 'a`
-LL |     Ref1Variant1(RequireOutlives<'a, T>)
+LL |     Ref1Variant1(RequireOutlives<'a, T>),
    |                  ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:23:25
+  --> $DIR/regions-enum-not-wf.rs:24:25
    |
 LL | enum Ref2<'a, T> {
    |               - help: consider adding an explicit lifetime bound...: `T: 'a`
@@ -16,25 +16,13 @@
    |                         ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:35:1
-   |
-LL |   enum RefDouble<'a, 'b, T> {
-   |   ^                      - help: consider adding an explicit lifetime bound...: `T: 'b`
-   |  _|
-   | |
-LL | |     RefDoubleVariant1(&'a RequireOutlives<'b, T>)
-LL | |
-LL | | }
-   | |_^ ...so that the type `T` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:36:23
+  --> $DIR/regions-enum-not-wf.rs:37:23
    |
 LL | enum RefDouble<'a, 'b, T> {
    |                        - help: consider adding an explicit lifetime bound...: `T: 'b`
-LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>)
+LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>),
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs
index e912805..9912e88 100644
--- a/src/test/ui/regions/regions-normalize-in-where-clause-list.rs
+++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.rs
@@ -6,7 +6,8 @@
 }
 
 impl<'a, 'b> Project<'a, 'b> for ()
-    where 'a: 'b
+where
+    'a: 'b,
 {
     type Item = ();
 }
@@ -14,16 +15,18 @@
 // No error here, we have 'a: 'b. We used to report an error here
 // though, see https://github.com/rust-lang/rust/issues/45937.
 fn foo<'a: 'b, 'b>()
-    where <() as Project<'a, 'b>>::Item : Eq
+where
+    <() as Project<'a, 'b>>::Item: Eq,
 {
 }
 
 // Here we get an error: we need `'a: 'b`.
-fn bar<'a, 'b>() //~ ERROR cannot infer
-                 //~| ERROR cannot infer
-                 //~| ERROR cannot infer
-    where <() as Project<'a, 'b>>::Item : Eq
+fn bar<'a, 'b>()
+//~^ ERROR cannot infer
+//~| ERROR cannot infer
+where
+    <() as Project<'a, 'b>>::Item: Eq,
 {
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
index 10ecb8d..ddb2b31c 100644
--- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
+++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
@@ -1,87 +1,59 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:1
    |
 LL | / fn bar<'a, 'b>()
 LL | |
 LL | |
-LL | |     where <() as Project<'a, 'b>>::Item : Eq
-   | |____________________________________________^
+LL | | where
+LL | |     <() as Project<'a, 'b>>::Item: Eq,
+   | |______________________________________^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:8
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:8
    |
 LL | fn bar<'a, 'b>()
    |        ^^
-note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:12
+note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:12
    |
 LL | fn bar<'a, 'b>()
    |            ^^
 note: ...so that the types are compatible
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:1
    |
 LL | / fn bar<'a, 'b>()
 LL | |
 LL | |
-LL | |     where <() as Project<'a, 'b>>::Item : Eq
-   | |____________________________________________^
+LL | | where
+LL | |     <() as Project<'a, 'b>>::Item: Eq,
+   | |______________________________________^
    = note: expected `Project<'a, 'b>`
               found `Project<'_, '_>`
 
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
-   |
-LL | / fn bar<'a, 'b>()
-LL | |
-LL | |
-LL | |     where <() as Project<'a, 'b>>::Item : Eq
-   | |____________________________________________^
-   |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:8
-   |
-LL | fn bar<'a, 'b>()
-   |        ^^
-note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:12
-   |
-LL | fn bar<'a, 'b>()
-   |            ^^
-note: ...so that the types are compatible
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
-   |
-LL | / fn bar<'a, 'b>()
-LL | |
-LL | |
-LL | |     where <() as Project<'a, 'b>>::Item : Eq
-   | |____________________________________________^
-   = note: expected `Project<'a, 'b>`
-              found `Project<'_, '_>`
-
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:4
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:4
    |
 LL | fn bar<'a, 'b>()
    |    ^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:8
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:8
    |
 LL | fn bar<'a, 'b>()
    |        ^^
-note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:12
+note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12...
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:12
    |
 LL | fn bar<'a, 'b>()
    |            ^^
 note: ...so that the types are compatible
-  --> $DIR/regions-normalize-in-where-clause-list.rs:22:4
+  --> $DIR/regions-normalize-in-where-clause-list.rs:24:4
    |
 LL | fn bar<'a, 'b>()
    |    ^^^
    = note: expected `Project<'a, 'b>`
               found `Project<'_, '_>`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0495`.
diff --git a/src/test/ui/regions/regions-trait-1.rs b/src/test/ui/regions/regions-trait-1.rs
index 0da8ac5..b6dab1c 100644
--- a/src/test/ui/regions/regions-trait-1.rs
+++ b/src/test/ui/regions/regions-trait-1.rs
@@ -1,30 +1,33 @@
-#![feature(box_syntax)]
+// check-pass
 
-struct Ctxt { v: usize }
+struct Ctxt {
+    v: usize,
+}
 
 trait GetCtxt {
     // Here the `&` is bound in the method definition:
     fn get_ctxt(&self) -> &Ctxt;
 }
 
-struct HasCtxt<'a> { c: &'a Ctxt }
-
-impl<'a> GetCtxt for HasCtxt<'a> {
-
-    // Here an error occurs because we used `&self` but
-    // the definition used `&`:
-    fn get_ctxt(&self) -> &'a Ctxt { //~ ERROR method not compatible with trait
-        self.c
-    }
-
+struct HasCtxt<'a> {
+    c: &'a Ctxt,
 }
 
-fn get_v(gc: Box<dyn GetCtxt>) -> usize {
+impl<'a> GetCtxt for HasCtxt<'a> {
+    // Ok: Have implied bound of WF(&'b HasCtxt<'a>)
+    // so know 'a: 'b
+    // so know &'a Ctxt <: &'b Ctxt
+    fn get_ctxt<'b>(&'b self) -> &'a Ctxt {
+        self.c
+    }
+}
+
+fn get_v(gc: Box<dyn GetCtxt + '_>) -> usize {
     gc.get_ctxt().v
 }
 
 fn main() {
     let ctxt = Ctxt { v: 22 };
     let hc = HasCtxt { c: &ctxt };
-    assert_eq!(get_v(box hc as Box<dyn GetCtxt>), 22);
+    assert_eq!(get_v(Box::new(hc) as Box<dyn GetCtxt>), 22);
 }
diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr
deleted file mode 100644
index 92d96a7..0000000
--- a/src/test/ui/regions/regions-trait-1.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0308]: method not compatible with trait
-  --> $DIR/regions-trait-1.rs:16:5
-   |
-LL |     fn get_ctxt(&self) -> &'a Ctxt {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected fn pointer `fn(&HasCtxt<'a>) -> &Ctxt`
-              found fn pointer `fn(&HasCtxt<'a>) -> &'a Ctxt`
-note: the lifetime `'a` as defined on the impl at 12:6...
-  --> $DIR/regions-trait-1.rs:12:6
-   |
-LL | impl<'a> GetCtxt for HasCtxt<'a> {
-   |      ^^
-note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 16:5
-  --> $DIR/regions-trait-1.rs:16:5
-   |
-LL |     fn get_ctxt(&self) -> &'a Ctxt {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr
index f819faa..eac2461 100644
--- a/src/test/ui/reject-specialized-drops-8142.stderr
+++ b/src/test/ui/reject-specialized-drops-8142.stderr
@@ -1,15 +1,3 @@
-error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
-  --> $DIR/reject-specialized-drops-8142.rs:67:21
-   |
-LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
-   |                     ^^^^^
-   |
-note: the implementor must specify the same requirement
-  --> $DIR/reject-specialized-drops-8142.rs:21:1
-   |
-LL | union Union<T: Copy> { f: T }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not
   --> $DIR/reject-specialized-drops-8142.rs:23:20
    |
@@ -145,6 +133,18 @@
 LL | struct TupleStruct<T>(T);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not
+  --> $DIR/reject-specialized-drops-8142.rs:67:21
+   |
+LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT
+   |                     ^^^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/reject-specialized-drops-8142.rs:21:1
+   |
+LL | union Union<T: Copy> { f: T }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 11 previous errors
 
 Some errors have detailed explanations: E0308, E0366, E0367, E0495.
diff --git a/src/test/ui/resolve/issue-3907-2.stderr b/src/test/ui/resolve/issue-3907-2.stderr
index bd6e9d5..782cfee 100644
--- a/src/test/ui/resolve/issue-3907-2.stderr
+++ b/src/test/ui/resolve/issue-3907-2.stderr
@@ -2,12 +2,13 @@
   --> $DIR/issue-3907-2.rs:11:12
    |
 LL | fn bar(_x: Foo) {}
-   |            ^^^ the trait `issue_3907::Foo` cannot be made into an object
-   | 
-  ::: $DIR/auxiliary/issue-3907.rs:2:8
+   |            ^^^ `issue_3907::Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/auxiliary/issue-3907.rs:2:8
    |
 LL |     fn bar();
-   |        --- the trait cannot be made into an object because associated function `bar` has no `self` parameter
+   |        ^^^ the trait cannot be made into an object because associated function `bar` has no `self` parameter
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr
index 2a6b545..7507272 100644
--- a/src/test/ui/resolve/issue-54379.stderr
+++ b/src/test/ui/resolve/issue-54379.stderr
@@ -8,10 +8,12 @@
    |                    `..` must be at the end and cannot have a trailing comma
 
 error: expected `,`
-  --> $DIR/issue-54379.rs:9:24
+  --> $DIR/issue-54379.rs:9:28
    |
 LL |         MyStruct { .., Some(_) } => {},
-   |                        ^^^^
+   |         --------           ^
+   |         |
+   |         while parsing the fields for this pattern
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
index 7f8151d..5de8eb2 100644
--- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
+++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr
@@ -48,6 +48,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index 32eff15..807dadf 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -4,14 +4,27 @@
 LL |         n::Z;
    |         ^^^^
    |
-help: try using one of the enum's variants
+note: the enum is defined here
+  --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         m::Z::Fn;
-   |         ^^^^^^^^
-LL |         m::Z::Struct;
-   |         ^^^^^^^^^^^^
+LL | /         pub(in m) enum Z {
+LL | |             Fn(u8),
+LL | |             Struct {
+LL | |                 s: u8,
+LL | |             },
+LL | |             Unit,
+LL | |         }
+   | |_________^
+help: you might have meant to use the following enum variant
+   |
 LL |         m::Z::Unit;
    |         ^^^^^^^^^^
+help: the following enum variants are available
+   |
+LL |         (m::Z::Fn(/* fields */));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         (m::Z::Struct { /* fields */ });
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0423]: expected value, found enum `Z`
   --> $DIR/privacy-enum-ctor.rs:25:9
@@ -19,14 +32,27 @@
 LL |         Z;
    |         ^
    |
-help: try using one of the enum's variants
+note: the enum is defined here
+  --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         m::Z::Fn;
-   |         ^^^^^^^^
-LL |         m::Z::Struct;
-   |         ^^^^^^^^^^^^
+LL | /         pub(in m) enum Z {
+LL | |             Fn(u8),
+LL | |             Struct {
+LL | |                 s: u8,
+LL | |             },
+LL | |             Unit,
+LL | |         }
+   | |_________^
+help: you might have meant to use the following enum variant
+   |
 LL |         m::Z::Unit;
    |         ^^^^^^^^^^
+help: the following enum variants are available
+   |
+LL |         (m::Z::Fn(/* fields */));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         (m::Z::Struct { /* fields */ });
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0423]: expected value, found struct variant `Z::Struct`
   --> $DIR/privacy-enum-ctor.rs:29:20
@@ -48,14 +74,27 @@
 LL |     let _: E = m::E;
    |                ^^^^
    |
-help: try using one of the enum's variants
+note: the enum is defined here
+  --> $DIR/privacy-enum-ctor.rs:2:5
    |
-LL |     let _: E = E::Fn;
-   |                ^^^^^
-LL |     let _: E = E::Struct;
-   |                ^^^^^^^^^
+LL | /     pub enum E {
+LL | |         Fn(u8),
+LL | |         Struct {
+LL | |             s: u8,
+LL | |         },
+LL | |         Unit,
+LL | |     }
+   | |_____^
+help: you might have meant to use the following enum variant
+   |
 LL |     let _: E = E::Unit;
    |                ^^^^^^^
+help: the following enum variants are available
+   |
+LL |     let _: E = (E::Fn(/* fields */));
+   |                ^^^^^^^^^^^^^^^^^^^^^
+LL |     let _: E = (E::Struct { /* fields */ });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: a function with a similar name exists
    |
 LL |     let _: E = m::f;
@@ -84,14 +123,27 @@
 LL |     let _: E = E;
    |                ^
    |
-help: try using one of the enum's variants
+note: the enum is defined here
+  --> $DIR/privacy-enum-ctor.rs:2:5
    |
-LL |     let _: E = E::Fn;
-   |                ^^^^^
-LL |     let _: E = E::Struct;
-   |                ^^^^^^^^^
+LL | /     pub enum E {
+LL | |         Fn(u8),
+LL | |         Struct {
+LL | |             s: u8,
+LL | |         },
+LL | |         Unit,
+LL | |     }
+   | |_____^
+help: you might have meant to use the following enum variant
+   |
 LL |     let _: E = E::Unit;
    |                ^^^^^^^
+help: the following enum variants are available
+   |
+LL |     let _: E = (E::Fn(/* fields */));
+   |                ^^^^^^^^^^^^^^^^^^^^^
+LL |     let _: E = (E::Struct { /* fields */ });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider importing one of these items instead
    |
 LL | use std::f32::consts::E;
@@ -134,14 +186,27 @@
 LL |     let _: Z = m::n::Z;
    |                ^^^^^^^
    |
-help: try using one of the enum's variants
+note: the enum is defined here
+  --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |     let _: Z = m::Z::Fn;
-   |                ^^^^^^^^
-LL |     let _: Z = m::Z::Struct;
-   |                ^^^^^^^^^^^^
+LL | /         pub(in m) enum Z {
+LL | |             Fn(u8),
+LL | |             Struct {
+LL | |                 s: u8,
+LL | |             },
+LL | |             Unit,
+LL | |         }
+   | |_________^
+help: you might have meant to use the following enum variant
+   |
 LL |     let _: Z = m::Z::Unit;
    |                ^^^^^^^^^^
+help: the following enum variants are available
+   |
+LL |     let _: Z = (m::Z::Fn(/* fields */));
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _: Z = (m::Z::Struct { /* fields */ });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:61:12
diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs
similarity index 100%
rename from src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs
diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs
similarity index 100%
rename from src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs
diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs
similarity index 100%
rename from src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs
diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs
similarity index 100%
rename from src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs
diff --git a/src/test/ui/rfc1445/allow-use-behind-cousin-variant.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs
similarity index 100%
rename from src/test/ui/rfc1445/allow-use-behind-cousin-variant.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-use-behind-cousin-variant.rs
diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
similarity index 100%
rename from src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
diff --git a/src/test/ui/rfc1445/feature-gate.no_gate.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr
similarity index 100%
rename from src/test/ui/rfc1445/feature-gate.no_gate.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr
diff --git a/src/test/ui/rfc1445/feature-gate.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.rs
similarity index 100%
rename from src/test/ui/rfc1445/feature-gate.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.rs
diff --git a/src/test/ui/rfc1445/feature-gate.with_gate.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr
similarity index 100%
rename from src/test/ui/rfc1445/feature-gate.with_gate.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/feature-gate.with_gate.stderr
diff --git a/src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs
similarity index 100%
rename from src/test/ui/rfc1445/fn-ptr-is-structurally-matchable.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-structurally-matchable.rs
diff --git a/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
similarity index 100%
rename from src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
diff --git a/src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
similarity index 100%
rename from src/test/ui/rfc1445/issue-61188-match-slice-forbidden-without-eq.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
similarity index 100%
rename from src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
similarity index 100%
rename from src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs
similarity index 100%
rename from src/test/ui/rfc1445/issue-63479-match-fnptr.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs
diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
similarity index 100%
rename from src/test/ui/rfc1445/issue-63479-match-fnptr.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
diff --git a/src/test/ui/rfc1445/match-empty-array-allowed-without-eq-issue-62336.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs
similarity index 100%
rename from src/test/ui/rfc1445/match-empty-array-allowed-without-eq-issue-62336.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-empty-array-allowed-without-eq-issue-62336.rs
diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs
similarity index 100%
rename from src/test/ui/rfc1445/match-forbidden-without-eq.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs
diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr
similarity index 100%
rename from src/test/ui/rfc1445/match-forbidden-without-eq.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr
diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs
similarity index 100%
rename from src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs
diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr
similarity index 100%
rename from src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr
diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
similarity index 100%
rename from src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr b/src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
similarity index 100%
rename from src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
diff --git a/src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs
similarity index 100%
rename from src/test/ui/rfc1445/phantom-data-is-structurally-matchable.rs
rename to src/test/ui/rfc-1445-restrict-constants-in-patterns/phantom-data-is-structurally-matchable.rs
diff --git a/src/test/ui/rfc1717/missing-link-attr.rs b/src/test/ui/rfc-1717-dllimport/missing-link-attr.rs
similarity index 100%
rename from src/test/ui/rfc1717/missing-link-attr.rs
rename to src/test/ui/rfc-1717-dllimport/missing-link-attr.rs
diff --git a/src/test/ui/rfc1717/missing-link-attr.stderr b/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr
similarity index 100%
rename from src/test/ui/rfc1717/missing-link-attr.stderr
rename to src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr
diff --git a/src/test/ui/rfc1717/multiple-renames.rs b/src/test/ui/rfc-1717-dllimport/multiple-renames.rs
similarity index 100%
rename from src/test/ui/rfc1717/multiple-renames.rs
rename to src/test/ui/rfc-1717-dllimport/multiple-renames.rs
diff --git a/src/test/ui/rfc1717/multiple-renames.stderr b/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr
similarity index 100%
rename from src/test/ui/rfc1717/multiple-renames.stderr
rename to src/test/ui/rfc-1717-dllimport/multiple-renames.stderr
diff --git a/src/test/ui/rfc1717/rename-to-empty.rs b/src/test/ui/rfc-1717-dllimport/rename-to-empty.rs
similarity index 100%
rename from src/test/ui/rfc1717/rename-to-empty.rs
rename to src/test/ui/rfc-1717-dllimport/rename-to-empty.rs
diff --git a/src/test/ui/rfc1717/rename-to-empty.stderr b/src/test/ui/rfc-1717-dllimport/rename-to-empty.stderr
similarity index 100%
rename from src/test/ui/rfc1717/rename-to-empty.stderr
rename to src/test/ui/rfc-1717-dllimport/rename-to-empty.stderr
diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfc-2005-default-binding-mode/for.rs
index aa42c7b..d6c5a13 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/for.rs
+++ b/src/test/ui/rfc-2005-default-binding-mode/for.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 struct Foo {}
 
 pub fn main() {
diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr
index ef62431..9cc20a7 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/for.stderr
+++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of a shared reference
-  --> $DIR/for.rs:8:23
+  --> $DIR/for.rs:6:23
    |
 LL |     for (n, mut m) in &tups {
    |             -----     ^^^^^
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
index cf8ca57..0291a52 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr
@@ -1,10 +1,27 @@
 warning: skipping const checks
    |
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9
+   |
+LL |     let ptr: fn() -> L = attributed;
+   |         ^^^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
+   |
+LL |     ptr()
+   |     ^^^
+help: skipping check for `const_fn_fn_ptr_basics` feature
+  --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26
+   |
+LL |     let ptr: fn() -> L = attributed;
+   |                          ^^^^^^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
    |
 LL |     ptr()
    |     ^^^^^
 
-warning: 1 warning emitted
+error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
+
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs
index 781cdb7..6de08f6 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.rs
@@ -5,17 +5,18 @@
 #![allow(dead_code)]
 
 trait Dummy<'a> {
-  type Out;
+    type Out;
 }
 impl<'a, T> Dummy<'a> for T
-where T: 'a
+where
+    T: 'a,
 {
-  type Out = ();
+    type Out = ();
 }
 type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
 
 enum Ref1<'a, T> {
-    Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough
+    Ref1Variant1(RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
 }
 
 enum Ref2<'a, T> {
@@ -23,18 +24,18 @@
     Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
 }
 
-enum RefOk<'a, T:'a> {
-    RefOkVariant1(&'a T)
+enum RefOk<'a, T: 'a> {
+    RefOkVariant1(&'a T),
 }
 
 // This is now well formed. RFC 2093
 enum RefIndirect<'a, T> {
-    RefIndirectVariant1(isize, RefOk<'a,T>)
+    RefIndirectVariant1(isize, RefOk<'a, T>),
 }
 
-enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309]
-    RefDoubleVariant1(&'a RequireOutlives<'b, T>)
-        //~^ the parameter type `T` may not live long enough [E0309]
+enum RefDouble<'a, 'b, T> {
+    RefDoubleVariant1(&'a RequireOutlives<'b, T>),
+    //~^ the parameter type `T` may not live long enough [E0309]
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
index e32a36f..36686ea 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr
@@ -1,13 +1,13 @@
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:18:18
+  --> $DIR/regions-enum-not-wf.rs:19:18
    |
 LL | enum Ref1<'a, T> {
    |               - help: consider adding an explicit lifetime bound...: `T: 'a`
-LL |     Ref1Variant1(RequireOutlives<'a, T>)
+LL |     Ref1Variant1(RequireOutlives<'a, T>),
    |                  ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:23:25
+  --> $DIR/regions-enum-not-wf.rs:24:25
    |
 LL | enum Ref2<'a, T> {
    |               - help: consider adding an explicit lifetime bound...: `T: 'a`
@@ -16,25 +16,13 @@
    |                         ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:35:1
-   |
-LL |   enum RefDouble<'a, 'b, T> {
-   |   ^                      - help: consider adding an explicit lifetime bound...: `T: 'b`
-   |  _|
-   | |
-LL | |     RefDoubleVariant1(&'a RequireOutlives<'b, T>)
-LL | |
-LL | | }
-   | |_^ ...so that the type `T` will meet its required lifetime bounds
-
-error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/regions-enum-not-wf.rs:36:23
+  --> $DIR/regions-enum-not-wf.rs:37:23
    |
 LL | enum RefDouble<'a, 'b, T> {
    |                        - help: consider adding an explicit lifetime bound...: `T: 'b`
-LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>)
+LL |     RefDoubleVariant1(&'a RequireOutlives<'b, T>),
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/meta.rs b/src/test/ui/rfc-2126-extern-absolute-paths/meta.rs
deleted file mode 100644
index 1fb5878..0000000
--- a/src/test/ui/rfc-2126-extern-absolute-paths/meta.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// edition:2018
-
-// Tests that `meta` is allowed, even if the crate doesn't exist
-// yet (i.e., it causes a different error than `not-allowed.rs`).
-use meta; //~ ERROR can't find crate for `meta`
-
-fn main() {}
diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr
deleted file mode 100644
index eb4b9de..0000000
--- a/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0463]: can't find crate for `meta`
-  --> $DIR/meta.rs:5:5
-   |
-LL | use meta;
-   |     ^^^^ can't find crate
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr
index bfce180..bd6778c 100644
--- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr
+++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr
@@ -2,7 +2,7 @@
   --> $DIR/non-existent-3.rs:3:5
    |
 LL | use ycrate;
-   |     ^^^^^^ no `ycrate` external crate
+   |     ^^^^^^ no external crate `ycrate`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr
index 6d2b450..a66330c 100644
--- a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr
+++ b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr
@@ -2,7 +2,7 @@
   --> $DIR/not-allowed.rs:5:5
    |
 LL | use alloc;
-   |     ^^^^^ no `alloc` external crate
+   |     ^^^^^ no external crate `alloc`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index d38a3ab..bd39650 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -507,6 +507,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/disallowed-positions.rs:22:12
diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs
index 1217f89..a547d09 100644
--- a/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs
+++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs
@@ -8,8 +8,8 @@
         #[allow(unused_mut)] a: i32,
         #[cfg(something)] b: i32,
         #[cfg_attr(something, cfg(nothing))] c: i32,
-        #[deny(unused_mut)] d: i32,
-        #[forbid(unused_mut)] #[warn(unused_mut)] ...
+        #[forbid(unused_mut)] d: i32,
+        #[deny(unused_mut)] #[warn(unused_mut)] ...
     );
 }
 
@@ -17,16 +17,16 @@
     #[allow(unused_mut)] a: i32,
     #[cfg(something)] b: i32,
     #[cfg_attr(something, cfg(nothing))] c: i32,
-    #[deny(unused_mut)] d: i32,
-    #[forbid(unused_mut)] #[warn(unused_mut)] e: i32
+    #[forbid(unused_mut)] d: i32,
+    #[deny(unused_mut)] #[warn(unused_mut)] e: i32
 );
 
 pub fn foo(
     #[allow(unused_mut)] a: i32,
     #[cfg(something)] b: i32,
     #[cfg_attr(something, cfg(nothing))] c: i32,
-    #[deny(unused_mut)] d: i32,
-    #[forbid(unused_mut)] #[warn(unused_mut)] _e: i32
+    #[forbid(unused_mut)] d: i32,
+    #[deny(unused_mut)] #[warn(unused_mut)] _e: i32
 ) {}
 
 // self
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
new file mode 100644
index 0000000..af35bc2
--- /dev/null
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
@@ -0,0 +1,18 @@
+// Tests #73631: closures inherit `#[target_feature]` annotations
+
+// check-pass
+// only-x86_64
+
+#![feature(target_feature_11)]
+
+#[target_feature(enable="avx")]
+fn also_use_avx() {
+    println!("Hello from AVX")
+}
+
+#[target_feature(enable="avx")]
+fn use_avx() -> Box<dyn Fn()> {
+    Box::new(|| also_use_avx())
+}
+
+fn main() {}
diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr
index 85da2c6..35a65fa 100644
--- a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr
@@ -1,31 +1,36 @@
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/arbitrary-self-types-not-object-safe.rs:33:32
    |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |                                ^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18
+   |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
 LL |     fn foo(self: &Rc<Self>) -> usize;
-   |                  ---------
-   |                  |
-   |                  ...because method `foo`'s `self` parameter cannot be dispatched on
-   |                  help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
-...
-LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
-   |                                ^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
 
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/arbitrary-self-types-not-object-safe.rs:33:13
    |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18
+   |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
 LL |     fn foo(self: &Rc<Self>) -> usize;
-   |                  ---------
-   |                  |
-   |                  ...because method `foo`'s `self` parameter cannot be dispatched on
-   |                  help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
-...
-LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
-   |             ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
-   |
+   |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
    = note: required because of the requirements on the impl of `CoerceUnsized<Rc<dyn Foo>>` for `Rc<usize>`
    = note: required by cast to type `Rc<dyn Foo>`
 
diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr
index c4cde2c..a74752c 100644
--- a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr
@@ -1,17 +1,19 @@
 error[E0038]: the trait `Foo` cannot be made into an object
   --> $DIR/arbitrary-self-types-not-object-safe.rs:33:13
    |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:8:18
+   |
 LL | trait Foo {
    |       --- this trait cannot be made into an object...
 LL |     fn foo(self: &Rc<Self>) -> usize;
-   |                  ---------
-   |                  |
-   |                  ...because method `foo`'s `self` parameter cannot be dispatched on
-   |                  help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
-...
-LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
-   |             ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
-   |
+   |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
    = note: required because of the requirements on the impl of `CoerceUnsized<Rc<dyn Foo>>` for `Rc<usize>`
    = note: required by cast to type `Rc<dyn Foo>`
 
diff --git a/src/test/ui/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs
index 3b1eb9e..81e557d 100644
--- a/src/test/ui/self/self-in-typedefs.rs
+++ b/src/test/ui/self/self-in-typedefs.rs
@@ -1,7 +1,4 @@
 // build-pass (FIXME(62277): could be check-pass?)
-
-#![feature(untagged_unions)]
-
 #![allow(dead_code)]
 
 use std::mem::ManuallyDrop;
diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr
index c27bdf0..63b70f7 100644
--- a/src/test/ui/shift-various-bad-types.stderr
+++ b/src/test/ui/shift-various-bad-types.stderr
@@ -30,7 +30,7 @@
    |            |
    |            expected due to this
    |
-help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
+help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit
    |
 LL |     let _: i32 = (22_i64 >> 1_i32).try_into().unwrap();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
index a719b31..7d68af4 100644
--- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -49,8 +49,8 @@
         simd_select(m4, 0u32, 1u32);
         //~^ ERROR found non-SIMD `u32`
 
-        simd_select_bitmask(0u8, x, x);
-        //~^ ERROR mask length `8` != other vector length `4`
+        simd_select_bitmask(0u16, x, x);
+        //~^ ERROR mask length `16` != other vector length `4`
         //
         simd_select_bitmask(0u8, 1u32, 2u32);
         //~^ ERROR found non-SIMD `u32`
diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
index f68c969d..a1ef0bb 100644
--- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
+++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr
@@ -22,11 +22,11 @@
 LL |         simd_select(m4, 0u32, 1u32);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4`
   --> $DIR/simd-intrinsic-generic-select.rs:52:9
    |
-LL |         simd_select_bitmask(0u8, x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_select_bitmask(0u16, x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
   --> $DIR/simd-intrinsic-generic-select.rs:55:9
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.rs b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
new file mode 100644
index 0000000..8a53345
--- /dev/null
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.rs
@@ -0,0 +1,191 @@
+// build-fail
+#![allow(non_camel_case_types)]
+#![feature(repr_simd, platform_intrinsics)]
+
+// Test for #73542 to verify out-of-bounds shuffle vectors do not compile.
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x2(u8, u8);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x4(u8, u8, u8, u8);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x16(
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x32(
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x64(
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+    u8,
+);
+
+// Test vectors by lane size. Since LLVM does not distinguish between a shuffle
+// over two f32s and a shuffle over two u64s, or any other such combination,
+// it is not necessary to test every possible vector, only lane counts.
+macro_rules! test_shuffle_lanes {
+    ($n:literal, $x:ident, $y:ident, $t:tt) => {
+        unsafe {
+                let shuffle: $x = {
+                    const ARR: [u32; $n] = {
+                        let mut arr = [0; $n];
+                        arr[0] = $n * 2;
+                        arr
+                    };
+                    extern "platform-intrinsic" {
+                        pub fn $y<T, U>(x: T, y: T, idx: [u32; $n]) -> U;
+                    }
+                    let vec1 = $x$t;
+                    let vec2 = $x$t;
+                    $y(vec1, vec2, ARR)
+                };
+        }
+    }
+}
+//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle2` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle4` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle8` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle16` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle32` intrinsic
+//~| ERROR: invalid monomorphization of `simd_shuffle64` intrinsic
+// Because the test is mostly embedded in a macro, all the errors have the same origin point.
+// And unfortunately, standard comments, as in the UI test harness, disappear in macros!
+
+fn main() {
+    test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1));
+    test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1));
+    test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1));
+    test_shuffle_lanes!(16, u8x16, simd_shuffle16,
+        (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+    test_shuffle_lanes!(32, u8x32, simd_shuffle32,
+        (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+         15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+    test_shuffle_lanes!(64, u8x64, simd_shuffle64,
+        (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49,
+         48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
+         32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
+         16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+}
diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.stderr b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
new file mode 100644
index 0000000..4806f2c
--- /dev/null
+++ b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr
@@ -0,0 +1,76 @@
+error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: shuffle index #0 is out of bounds (limit 4)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                     $y(vec1, vec2, ARR)
+   |                     ^^^^^^^^^^^^^^^^^^^
+...
+LL |     test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1));
+   |     ---------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: shuffle index #0 is out of bounds (limit 8)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                     $y(vec1, vec2, ARR)
+   |                     ^^^^^^^^^^^^^^^^^^^
+...
+LL |     test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1));
+   |     ---------------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: shuffle index #0 is out of bounds (limit 16)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                     $y(vec1, vec2, ARR)
+   |                     ^^^^^^^^^^^^^^^^^^^
+...
+LL |     test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1));
+   |     ---------------------------------------------------------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle16` intrinsic: shuffle index #0 is out of bounds (limit 32)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                       $y(vec1, vec2, ARR)
+   |                       ^^^^^^^^^^^^^^^^^^^
+...
+LL | /     test_shuffle_lanes!(16, u8x16, simd_shuffle16,
+LL | |         (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+   | |_________________________________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle32` intrinsic: shuffle index #0 is out of bounds (limit 64)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                       $y(vec1, vec2, ARR)
+   |                       ^^^^^^^^^^^^^^^^^^^
+...
+LL | /     test_shuffle_lanes!(32, u8x32, simd_shuffle32,
+LL | |         (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
+LL | |          15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+   | |_____________________________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0511]: invalid monomorphization of `simd_shuffle64` intrinsic: shuffle index #0 is out of bounds (limit 128)
+  --> $DIR/shuffle-not-out-of-bounds.rs:163:21
+   |
+LL |                       $y(vec1, vec2, ARR)
+   |                       ^^^^^^^^^^^^^^^^^^^
+...
+LL | /     test_shuffle_lanes!(64, u8x64, simd_shuffle64,
+LL | |         (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49,
+LL | |          48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
+LL | |          32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
+LL | |          16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
+   | |_________________________________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0511`.
diff --git a/src/test/ui/simd/simd-intrinsic-generic-select.rs b/src/test/ui/simd/simd-intrinsic-generic-select.rs
index dc9ec5d..b850cf9 100644
--- a/src/test/ui/simd/simd-intrinsic-generic-select.rs
+++ b/src/test/ui/simd/simd-intrinsic-generic-select.rs
@@ -167,4 +167,29 @@
         let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7);
         assert_eq!(r, e);
     }
+
+    unsafe {
+        let a = u32x4(0, 1, 2, 3);
+        let b = u32x4(4, 5, 6, 7);
+
+        let r: u32x4 = simd_select_bitmask(0u8, a, b);
+        let e = b;
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0xfu8, a, b);
+        let e = a;
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0b0101u8, a, b);
+        let e = u32x4(0, 5, 2, 7);
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0b1010u8, a, b);
+        let e = u32x4(4, 1, 6, 3);
+        assert_eq!(r, e);
+
+        let r: u32x4 = simd_select_bitmask(0b1100u8, a, b);
+        let e = u32x4(4, 5, 2, 3);
+        assert_eq!(r, e);
+    }
 }
diff --git a/src/test/ui/slice-to-vec-comparison.rs b/src/test/ui/slice-to-vec-comparison.rs
new file mode 100644
index 0000000..7026a49
--- /dev/null
+++ b/src/test/ui/slice-to-vec-comparison.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let a = &[];
+    let b: &Vec<u8> = &vec![];
+    a > b;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/slice-to-vec-comparison.stderr b/src/test/ui/slice-to-vec-comparison.stderr
new file mode 100644
index 0000000..e3b3b04
--- /dev/null
+++ b/src/test/ui/slice-to-vec-comparison.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/slice-to-vec-comparison.rs:4:9
+   |
+LL |     a > b;
+   |         ^ expected array of 0 elements, found struct `Vec`
+   |
+   = note: expected reference `&[_; 0]`
+              found reference `&Vec<u8>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
index 2a7dda7..ab1fa2a 100644
--- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
+++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
@@ -33,7 +33,7 @@
    |         ----- captured outer variable
 ...
 LL |         foo(f);
-   |             ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6 s:String]`, which does not implement the `Copy` trait
+   |             ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait
 
 error[E0505]: cannot move out of `f` because it is borrowed
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16
diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr
index 40c3219..5cda17f 100644
--- a/src/test/ui/span/issue-34264.stderr
+++ b/src/test/ui/span/issue-34264.stderr
@@ -53,13 +53,16 @@
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/issue-34264.rs:7:5
    |
-LL | fn foo(Option<i32>, String) {}
-   | --------------------------- defined here
-...
 LL |     foo(Some(42), 2, "");
    |     ^^^ --------  -  -- supplied 3 arguments
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/issue-34264.rs:1:4
+   |
+LL | fn foo(Option<i32>, String) {}
+   |    ^^^ -----------  ------
 
 error[E0308]: mismatched types
   --> $DIR/issue-34264.rs:8:13
@@ -70,13 +73,16 @@
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/issue-34264.rs:10:5
    |
-LL | fn bar(x, y: usize) {}
-   | ------------------- defined here
-...
 LL |     bar(1, 2, 3);
    |     ^^^ -  -  - supplied 3 arguments
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/issue-34264.rs:3:4
+   |
+LL | fn bar(x, y: usize) {}
+   |    ^^^ -  --------
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr
index f6344fb..b15da2c 100644
--- a/src/test/ui/span/missing-unit-argument.stderr
+++ b/src/test/ui/span/missing-unit-argument.stderr
@@ -12,34 +12,42 @@
 error[E0061]: this function takes 2 arguments but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:12:5
    |
-LL | fn foo(():(), ():()) {}
-   | -------------------- defined here
-...
 LL |     foo();
    |     ^^^-- supplied 0 arguments
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/missing-unit-argument.rs:1:4
+   |
+LL | fn foo(():(), ():()) {}
+   |    ^^^ -----  -----
 
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/missing-unit-argument.rs:13:5
    |
-LL | fn foo(():(), ():()) {}
-   | -------------------- defined here
-...
 LL |     foo(());
    |     ^^^ -- supplied 1 argument
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/missing-unit-argument.rs:1:4
+   |
+LL | fn foo(():(), ():()) {}
+   |    ^^^ -----  -----
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:14:5
    |
-LL | fn bar(():()) {}
-   | ------------- defined here
-...
 LL |     bar();
    |     ^^^-- supplied 0 arguments
    |
+note: function defined here
+  --> $DIR/missing-unit-argument.rs:2:4
+   |
+LL | fn bar(():()) {}
+   |    ^^^ -----
 help: expected the unit value `()`; create it with empty parentheses
    |
 LL |     bar(());
@@ -48,12 +56,14 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:15:7
    |
-LL |     fn baz(self, (): ()) { }
-   |     -------------------- defined here
-...
 LL |     S.baz();
    |       ^^^- supplied 0 arguments
    |
+note: associated function defined here
+  --> $DIR/missing-unit-argument.rs:6:8
+   |
+LL |     fn baz(self, (): ()) { }
+   |        ^^^ ----  ------
 help: expected the unit value `()`; create it with empty parentheses
    |
 LL |     S.baz(());
@@ -62,12 +72,14 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:16:7
    |
-LL |     fn generic<T>(self, _: T) { }
-   |     ------------------------- defined here
-...
 LL |     S.generic::<()>();
    |       ^^^^^^^------ supplied 0 arguments
    |
+note: associated function defined here
+  --> $DIR/missing-unit-argument.rs:7:8
+   |
+LL |     fn generic<T>(self, _: T) { }
+   |        ^^^^^^^    ----  ----
 help: expected the unit value `()`; create it with empty parentheses
    |
 LL |     S.generic::<()>(());
diff --git a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr
index 250f48f..17da34c 100644
--- a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr
+++ b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/cross-crate-defaults.stderr b/src/test/ui/specialization/cross-crate-defaults.stderr
index f18bc99..e368c2e 100644
--- a/src/test/ui/specialization/cross-crate-defaults.stderr
+++ b/src/test/ui/specialization/cross-crate-defaults.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs
index c043114..6eb2aa9 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-1.rs
+++ b/src/test/ui/specialization/deafult-associated-type-bound-1.rs
@@ -1,5 +1,6 @@
 // Check that we check that default associated types satisfy the required
 // bounds on them.
+// ignore-compare-mode-chalk
 
 #![feature(specialization)]
 //~^ WARNING `specialization` is incomplete
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
index 612e22c..4ca3d83 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
+++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
@@ -1,17 +1,18 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/deafult-associated-type-bound-1.rs:4:12
+  --> $DIR/deafult-associated-type-bound-1.rs:5:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/deafult-associated-type-bound-1.rs:18:5
+  --> $DIR/deafult-associated-type-bound-1.rs:19:5
    |
 LL |     type U: Clone;
-   |     -------------- required by `X::U`
+   |             ----- required by this bound in `X::U`
 ...
 LL |     default type U = str;
    |     ^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
index a14024c..2bc14db 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
+++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
@@ -6,12 +6,13 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0277]: can't compare `&'static B` with `B`
   --> $DIR/deafult-associated-type-bound-2.rs:16:5
    |
 LL |     type U: PartialEq<T>;
-   |     --------------------- required by `X::U`
+   |             ------------ required by this bound in `X::U`
 ...
 LL |     default type U = &'static B;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
index 8a94ea6..f14588e 100644
--- a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
+++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
@@ -6,7 +6,7 @@
 //~^^ WARNING the feature `generic_associated_types` is incomplete
 
 trait X {
-    type U<'a>: PartialEq<&'a Self>;
+    type U<'a>: PartialEq<&'a Self> where Self: 'a;
     fn unsafe_compare<'b>(x: Option<Self::U<'b>>, y: Option<&'b Self>) {
         match (x, y) {
             (Some(a), Some(b)) => a == b,
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
index 556feda..b5a1877 100644
--- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
+++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/deafult-generic-associated-type-bound.rs:4:12
@@ -18,8 +19,8 @@
 error[E0277]: can't compare `T` with `T`
   --> $DIR/deafult-generic-associated-type-bound.rs:19:5
    |
-LL |     type U<'a>: PartialEq<&'a Self>;
-   |     -------------------------------- required by `X::U`
+LL |     type U<'a>: PartialEq<&'a Self> where Self: 'a;
+   |                 ------------------- required by this bound in `X::U`
 ...
 LL |     default type U<'a> = &'a T;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T`
diff --git a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr
index 1b50329..d8b9c48 100644
--- a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr
+++ b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/defaultimpl/out-of-order.stderr b/src/test/ui/specialization/defaultimpl/out-of-order.stderr
index deae021..9ca9156 100644
--- a/src/test/ui/specialization/defaultimpl/out-of-order.stderr
+++ b/src/test/ui/specialization/defaultimpl/out-of-order.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr
index 46899ca..31d0e6e 100644
--- a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr
+++ b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/defaultimpl/projection.stderr b/src/test/ui/specialization/defaultimpl/projection.stderr
index 8629c6c..2d5c80d 100644
--- a/src/test/ui/specialization/defaultimpl/projection.stderr
+++ b/src/test/ui/specialization/defaultimpl/projection.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr
index 7958edd..3f1a549 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
   --> $DIR/specialization-no-default.rs:20:5
diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr
index dc377dd..163c935 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr
index 9d1eca1..250f001 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0046]: not all trait items implemented, missing: `foo_two`
   --> $DIR/specialization-trait-item-not-implemented.rs:18:1
diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
index 6b8e559..fb623c9 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope
   --> $DIR/specialization-trait-not-implemented.rs:22:29
diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr
index dcac310..57b90c4 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0277]: the trait bound `U: Eq` is not satisfied
   --> $DIR/specialization-wfcheck.rs:7:17
diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr
index 2449849..cbf0cef 100644
--- a/src/test/ui/specialization/defaultimpl/validation.stderr
+++ b/src/test/ui/specialization/defaultimpl/validation.stderr
@@ -16,6 +16,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error: impls of auto traits cannot be default
   --> $DIR/validation.rs:9:21
diff --git a/src/test/ui/specialization/issue-36804.stderr b/src/test/ui/specialization/issue-36804.stderr
index 744d882..783a38e 100644
--- a/src/test/ui/specialization/issue-36804.stderr
+++ b/src/test/ui/specialization/issue-36804.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/issue-38091-2.rs b/src/test/ui/specialization/issue-38091-2.rs
new file mode 100644
index 0000000..9ed0b24
--- /dev/null
+++ b/src/test/ui/specialization/issue-38091-2.rs
@@ -0,0 +1,28 @@
+// build-fail
+//~^ ERROR overflow evaluating the requirement `i32: Check`
+
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
+trait Iterate<'a> {
+    type Ty: Valid;
+    fn iterate(self);
+}
+impl<'a, T> Iterate<'a> for T
+where
+    T: Check,
+{
+    default type Ty = ();
+    default fn iterate(self) {}
+}
+
+trait Check {}
+impl<'a, T> Check for T where <T as Iterate<'a>>::Ty: Valid {}
+
+trait Valid {}
+
+impl Valid for () {}
+
+fn main() {
+    Iterate::iterate(0);
+}
diff --git a/src/test/ui/specialization/issue-38091-2.stderr b/src/test/ui/specialization/issue-38091-2.stderr
new file mode 100644
index 0000000..bd5ed49
--- /dev/null
+++ b/src/test/ui/specialization/issue-38091-2.stderr
@@ -0,0 +1,17 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-38091-2.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+
+error[E0275]: overflow evaluating the requirement `i32: Check`
+   |
+   = note: required because of the requirements on the impl of `Iterate` for `i32`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/specialization/issue-38091.rs b/src/test/ui/specialization/issue-38091.rs
new file mode 100644
index 0000000..5b39836
--- /dev/null
+++ b/src/test/ui/specialization/issue-38091.rs
@@ -0,0 +1,24 @@
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
+trait Iterate<'a> {
+    type Ty: Valid;
+    fn iterate(self);
+}
+impl<'a, T> Iterate<'a> for T
+where
+    T: Check,
+{
+    default type Ty = ();
+    //~^ ERROR the trait bound `(): Valid` is not satisfied
+    default fn iterate(self) {}
+}
+
+trait Check {}
+impl<'a, T> Check for T where <T as Iterate<'a>>::Ty: Valid {}
+
+trait Valid {}
+
+fn main() {
+    Iterate::iterate(0);
+}
diff --git a/src/test/ui/specialization/issue-38091.stderr b/src/test/ui/specialization/issue-38091.stderr
new file mode 100644
index 0000000..97e5775
--- /dev/null
+++ b/src/test/ui/specialization/issue-38091.stderr
@@ -0,0 +1,22 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-38091.rs:1:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+
+error[E0277]: the trait bound `(): Valid` is not satisfied
+  --> $DIR/issue-38091.rs:12:5
+   |
+LL |     type Ty: Valid;
+   |              ----- required by this bound in `Iterate::Ty`
+...
+LL |     default type Ty = ();
+   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/issue-39448.stderr b/src/test/ui/specialization/issue-39448.stderr
index f3bb69b..98e49b1 100644
--- a/src/test/ui/specialization/issue-39448.stderr
+++ b/src/test/ui/specialization/issue-39448.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0275]: overflow evaluating the requirement `T: FromA<U>`
   --> $DIR/issue-39448.rs:45:13
diff --git a/src/test/ui/specialization/issue-39618.stderr b/src/test/ui/specialization/issue-39618.stderr
index d40d17d..77a4580 100644
--- a/src/test/ui/specialization/issue-39618.stderr
+++ b/src/test/ui/specialization/issue-39618.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/issue-44861.stderr b/src/test/ui/specialization/issue-44861.stderr
index be7196a6..3935a4a 100644
--- a/src/test/ui/specialization/issue-44861.stderr
+++ b/src/test/ui/specialization/issue-44861.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-44861.rs:21:5
    |
 LL |     type Data2: CoerceUnsized<*const [u8]>;
-   |     --------------------------------------- required by `Smartass::Data2`
+   |                 -------------------------- required by this bound in `Smartass::Data2`
 ...
 LL |     default type Data2 = ();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `CoerceUnsized<*const [u8]>` is not implemented for `()`
diff --git a/src/test/ui/specialization/issue-50452.stderr b/src/test/ui/specialization/issue-50452.stderr
index c01817e..2f05c41 100644
--- a/src/test/ui/specialization/issue-50452.stderr
+++ b/src/test/ui/specialization/issue-50452.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr
index a7564ce..27070f8 100644
--- a/src/test/ui/specialization/issue-52050.stderr
+++ b/src/test/ui/specialization/issue-52050.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()`:
   --> $DIR/issue-52050.rs:28:1
diff --git a/src/test/ui/specialization/issue-59435.stderr b/src/test/ui/specialization/issue-59435.stderr
index ee5c061..f3f8b02 100644
--- a/src/test/ui/specialization/issue-59435.stderr
+++ b/src/test/ui/specialization/issue-59435.stderr
@@ -2,7 +2,7 @@
   --> $DIR/issue-59435.rs:11:5
    |
 LL |     type MyType: Default;
-   |     --------------------- required by `MyTrait::MyType`
+   |                  ------- required by this bound in `MyTrait::MyType`
 ...
 LL |     default type MyType = MyStruct;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `MyStruct`
diff --git a/src/test/ui/specialization/issue-63716-parse-async.stderr b/src/test/ui/specialization/issue-63716-parse-async.stderr
index 43620e1..cde1787 100644
--- a/src/test/ui/specialization/issue-63716-parse-async.stderr
+++ b/src/test/ui/specialization/issue-63716-parse-async.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/issue-70442.stderr b/src/test/ui/specialization/issue-70442.stderr
index f71e4c7..5ee82e9 100644
--- a/src/test/ui/specialization/issue-70442.stderr
+++ b/src/test/ui/specialization/issue-70442.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/non-defaulted-item-fail.stderr b/src/test/ui/specialization/non-defaulted-item-fail.stderr
index eae045b..85ccbd8 100644
--- a/src/test/ui/specialization/non-defaulted-item-fail.stderr
+++ b/src/test/ui/specialization/non-defaulted-item-fail.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default`
   --> $DIR/non-defaulted-item-fail.rs:30:5
diff --git a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr
index 7d08754..9605bd0 100644
--- a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr
+++ b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-assoc-fns.stderr b/src/test/ui/specialization/specialization-assoc-fns.stderr
index b127386..a7c0661 100644
--- a/src/test/ui/specialization/specialization-assoc-fns.stderr
+++ b/src/test/ui/specialization/specialization-assoc-fns.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-basics.stderr b/src/test/ui/specialization/specialization-basics.stderr
index ad00cd8..afb2af3 100644
--- a/src/test/ui/specialization/specialization-basics.stderr
+++ b/src/test/ui/specialization/specialization-basics.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-cross-crate.stderr b/src/test/ui/specialization/specialization-cross-crate.stderr
index 7481eed..c69130c 100644
--- a/src/test/ui/specialization/specialization-cross-crate.stderr
+++ b/src/test/ui/specialization/specialization-cross-crate.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-default-methods.stderr b/src/test/ui/specialization/specialization-default-methods.stderr
index 4fa19ad..ef6365e 100644
--- a/src/test/ui/specialization/specialization-default-methods.stderr
+++ b/src/test/ui/specialization/specialization-default-methods.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr
index 456eb6d..445bc16 100644
--- a/src/test/ui/specialization/specialization-default-projection.stderr
+++ b/src/test/ui/specialization/specialization-default-projection.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0308]: mismatched types
   --> $DIR/specialization-default-projection.rs:21:5
diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr
index 5acfb53..5ba38fa 100644
--- a/src/test/ui/specialization/specialization-default-types.stderr
+++ b/src/test/ui/specialization/specialization-default-types.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0308]: mismatched types
   --> $DIR/specialization-default-types.rs:15:9
diff --git a/src/test/ui/specialization/specialization-no-default.stderr b/src/test/ui/specialization/specialization-no-default.stderr
index bb8b2a6..711c1fd 100644
--- a/src/test/ui/specialization/specialization-no-default.stderr
+++ b/src/test/ui/specialization/specialization-no-default.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default`
   --> $DIR/specialization-no-default.rs:20:5
diff --git a/src/test/ui/specialization/specialization-on-projection.stderr b/src/test/ui/specialization/specialization-on-projection.stderr
index d91668d..d051ffe 100644
--- a/src/test/ui/specialization/specialization-on-projection.stderr
+++ b/src/test/ui/specialization/specialization-on-projection.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-out-of-order.stderr b/src/test/ui/specialization/specialization-out-of-order.stderr
index a17f9f1..785ec29 100644
--- a/src/test/ui/specialization/specialization-out-of-order.stderr
+++ b/src/test/ui/specialization/specialization-out-of-order.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-overlap-negative.stderr b/src/test/ui/specialization/specialization-overlap-negative.stderr
index 6141174..552b04a 100644
--- a/src/test/ui/specialization/specialization-overlap-negative.stderr
+++ b/src/test/ui/specialization/specialization-overlap-negative.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0751]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType<_>`:
   --> $DIR/specialization-overlap-negative.rs:9:1
diff --git a/src/test/ui/specialization/specialization-overlap-projection.stderr b/src/test/ui/specialization/specialization-overlap-projection.stderr
index 6f1a594..c92db73 100644
--- a/src/test/ui/specialization/specialization-overlap-projection.stderr
+++ b/src/test/ui/specialization/specialization-overlap-projection.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-overlap.stderr b/src/test/ui/specialization/specialization-overlap.stderr
index cf0f186..7e5c96a 100644
--- a/src/test/ui/specialization/specialization-overlap.stderr
+++ b/src/test/ui/specialization/specialization-overlap.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0119]: conflicting implementations of trait `Foo` for type `std::vec::Vec<_>`:
   --> $DIR/specialization-overlap.rs:5:1
diff --git a/src/test/ui/specialization/specialization-polarity.stderr b/src/test/ui/specialization/specialization-polarity.stderr
index c44af22..be01355 100644
--- a/src/test/ui/specialization/specialization-polarity.stderr
+++ b/src/test/ui/specialization/specialization-polarity.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0751]: found both positive and negative implementation of trait `Foo` for type `u8`:
   --> $DIR/specialization-polarity.rs:10:1
diff --git a/src/test/ui/specialization/specialization-projection-alias.stderr b/src/test/ui/specialization/specialization-projection-alias.stderr
index 0c3659a..6d2bca5 100644
--- a/src/test/ui/specialization/specialization-projection-alias.stderr
+++ b/src/test/ui/specialization/specialization-projection-alias.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-projection.stderr b/src/test/ui/specialization/specialization-projection.stderr
index c5c86f5..0f1ecf5 100644
--- a/src/test/ui/specialization/specialization-projection.stderr
+++ b/src/test/ui/specialization/specialization-projection.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-super-traits.stderr b/src/test/ui/specialization/specialization-super-traits.stderr
index 05bdfd4..165703d 100644
--- a/src/test/ui/specialization/specialization-super-traits.stderr
+++ b/src/test/ui/specialization/specialization-super-traits.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr
index 6284dd8..d30f7af2 100644
--- a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr
+++ b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr
index b177941..1762248 100644
--- a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr
+++ b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/specialization/specialization-translate-projections.stderr b/src/test/ui/specialization/specialization-translate-projections.stderr
index fbb28e6..94a0e79 100644
--- a/src/test/ui/specialization/specialization-translate-projections.stderr
+++ b/src/test/ui/specialization/specialization-translate-projections.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/static/static-mut-not-constant.rs b/src/test/ui/static/static-mut-not-constant.rs
index 84d401c..2091fff 100644
--- a/src/test/ui/static/static-mut-not-constant.rs
+++ b/src/test/ui/static/static-mut-not-constant.rs
@@ -2,6 +2,5 @@
 
 static mut a: Box<isize> = box 3;
 //~^ ERROR allocations are not allowed in statics
-//~| ERROR static contains unimplemented expression type
 
 fn main() {}
diff --git a/src/test/ui/static/static-mut-not-constant.stderr b/src/test/ui/static/static-mut-not-constant.stderr
index a618b49..a0fa245 100644
--- a/src/test/ui/static/static-mut-not-constant.stderr
+++ b/src/test/ui/static/static-mut-not-constant.stderr
@@ -4,15 +4,6 @@
 LL | static mut a: Box<isize> = box 3;
    |                            ^^^^^ allocation not allowed in statics
 
-error[E0019]: static contains unimplemented expression type
-  --> $DIR/static-mut-not-constant.rs:3:32
-   |
-LL | static mut a: Box<isize> = box 3;
-   |                                ^
-   |
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0010, E0019.
-For more information about an error, try `rustc --explain E0010`.
+For more information about this error, try `rustc --explain E0010`.
diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
index cc3a2b9..d826222 100644
--- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
+++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
@@ -5,8 +5,6 @@
    |             ^^^^^^^^ the trait `Bar` is not implemented for `()`
 LL |     5;
    |      - consider removing this semicolon
-   |
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index cec01fe..69e95ef 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -41,7 +41,7 @@
 LL | | where
 LL | |     G: Get<T>
    | |_____________^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6 g:G, dest:&mut T]` will meet its required lifetime bounds
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6]` will meet its required lifetime bounds
   --> $DIR/missing-lifetimes-in-signature.rs:25:37
    |
 LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
@@ -65,7 +65,7 @@
 LL | | where
 LL | |     G: Get<T>
    | |_____________^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6 g:G, dest:&mut T]` will meet its required lifetime bounds
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6]` will meet its required lifetime bounds
   --> $DIR/missing-lifetimes-in-signature.rs:47:45
    |
 LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
@@ -86,7 +86,7 @@
    |
 LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10 g:G, dest:&mut T]` will meet its required lifetime bounds
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10]` will meet its required lifetime bounds
   --> $DIR/missing-lifetimes-in-signature.rs:59:58
    |
 LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
@@ -108,7 +108,7 @@
   --> $DIR/missing-lifetimes-in-signature.rs:79:44
    |
 LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
-   |            -                               ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6 g:G, dest:&mut T]` will meet its required lifetime bounds
+   |            -                               ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6]` will meet its required lifetime bounds
    |            |
    |            help: consider adding an explicit lifetime bound...: `G: 'a`
 
diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs
index 394512c..4954a8a 100644
--- a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs
+++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs
@@ -1,5 +1,4 @@
-// Running rustfix would cause the same suggestion to be applied multiple times, which results in
-// invalid code.
+// check-pass
 
 trait Parent {
     type Ty;
@@ -15,11 +14,8 @@
 struct ParentWrapper<T>(T);
 
 impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
-    //~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
     type Ty = A;
     type Assoc = ChildWrapper<T::Assoc>;
-    //~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
-    //~| ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
 }
 
 fn main() {}
diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
deleted file mode 100644
index a8ea214..0000000
--- a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
+++ /dev/null
@@ -1,55 +0,0 @@
-error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
-  --> $DIR/missing-assoc-type-bound-restriction.rs:17:19
-   |
-LL | trait Parent {
-   |       ------ required by a bound in this
-LL |     type Ty;
-LL |     type Assoc: Child<Self::Ty>;
-   |                 --------------- required by this bound in `Parent`
-...
-LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
-   |                   ^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
-   |
-help: consider further restricting the associated type
-   |
-LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> where <T as Parent>::Assoc: Child<A> {
-   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
-  --> $DIR/missing-assoc-type-bound-restriction.rs:20:18
-   |
-LL | trait Parent {
-   |       ------ required by a bound in this
-LL |     type Ty;
-LL |     type Assoc: Child<Self::Ty>;
-   |                 --------------- required by this bound in `Parent`
-...
-LL |     type Assoc = ChildWrapper<T::Assoc>;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
-   |
-   = note: required because of the requirements on the impl of `Child<A>` for `ChildWrapper<<T as Parent>::Assoc>`
-help: consider further restricting the associated type
-   |
-LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> where <T as Parent>::Assoc: Child<A> {
-   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
-  --> $DIR/missing-assoc-type-bound-restriction.rs:20:5
-   |
-LL | trait Parent {
-   |       ------ required by a bound in this
-LL |     type Ty;
-LL |     type Assoc: Child<Self::Ty>;
-   |                 --------------- required by this bound in `Parent`
-...
-LL |     type Assoc = ChildWrapper<T::Assoc>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
-   |
-help: consider further restricting the associated type
-   |
-LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> where <T as Parent>::Assoc: Child<A> {
-   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
index c1eea56..8a9a1e5 100644
--- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
+++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
@@ -13,7 +13,7 @@
 LL |     let fp = BufWriter::new(fp);
    |              ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
    | 
-  ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL
+  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
    |                         ----- required by this bound in `BufWriter`
@@ -26,7 +26,7 @@
 LL |     let fp = BufWriter::new(fp);
    |              ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
    | 
-  ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL
+  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
    |                         ----- required by this bound in `BufWriter`
@@ -39,7 +39,7 @@
 LL |     writeln!(fp, "hello world").unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>`
    | 
-  ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL
+  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
    | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
diff --git a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr
index c3cfad7..797406f 100644
--- a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr
+++ b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr
@@ -1,29 +1,34 @@
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/object-unsafe-trait-references-self.rs:6:11
    |
-LL | trait Trait {
-   |       ----- this trait cannot be made into an object...
-LL |     fn baz(&self, _: Self) {}
-   |                      ---- ...because method `baz` references the `Self` type in this parameter
-LL |     fn bat(&self) -> Self {}
-   |                      ---- ...because method `bat` references the `Self` type in its return type
-...
 LL | fn bar(x: &dyn Trait) {}
-   |           ^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |           ^^^^^^^^^^ `Trait` cannot be made into an object
    |
    = help: consider moving `baz` to another trait
    = help: consider moving `bat` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-references-self.rs:2:22
+   |
+LL | trait Trait {
+   |       ----- this trait cannot be made into an object...
+LL |     fn baz(&self, _: Self) {}
+   |                      ^^^^ ...because method `baz` references the `Self` type in this parameter
+LL |     fn bat(&self) -> Self {}
+   |                      ^^^^ ...because method `bat` references the `Self` type in its return type
 
 error[E0038]: the trait `Other` cannot be made into an object
   --> $DIR/object-unsafe-trait-references-self.rs:10:11
    |
+LL | fn foo(x: &dyn Other) {}
+   |           ^^^^^^^^^^ `Other` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-references-self.rs:8:14
+   |
 LL | trait Other: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-LL | 
-LL | fn foo(x: &dyn Other) {}
-   |           ^^^^^^^^^^ the trait `Other` cannot be made into an object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr
index 58be596..67491b0 100644
--- a/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr
+++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-self.stderr
@@ -14,12 +14,16 @@
 error[E0038]: the trait `A` cannot be made into an object
   --> $DIR/object-unsafe-trait-should-use-self.rs:3:13
    |
+LL |     fn f(a: A) -> A;
+   |             ^ `A` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self.rs:2:10
+   |
 LL | trait A: Sized {
-   |       -  ----- ...because it requires `Self: Sized`
+   |       -  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-LL |     fn f(a: A) -> A;
-   |             ^ the trait `A` cannot be made into an object
 
 error: associated item referring to unboxed trait object for its own trait
   --> $DIR/object-unsafe-trait-should-use-self.rs:8:13
@@ -37,14 +41,21 @@
 error[E0038]: the trait `B` cannot be made into an object
   --> $DIR/object-unsafe-trait-should-use-self.rs:8:13
    |
+LL |     fn f(a: B) -> B;
+   |             ^ `B` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-self.rs:8:8
+   |
 LL | trait B {
    |       - this trait cannot be made into an object...
 LL |     fn f(a: B) -> B;
-   |        -    ^ the trait `B` cannot be made into an object
-   |        |
-   |        ...because associated function `f` has no `self` parameter
+   |        ^ ...because associated function `f` has no `self` parameter
+help: consider turning `f` into a method by giving it a `&self` argument
    |
-help: consider turning `f` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn f(&self, a: B) -> B;
+   |          ^^^^^^
+help: alternatively, consider constraining `f` so it does not apply to trait objects
    |
 LL |     fn f(a: B) -> B where Self: Sized;
    |                     ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed
index c4b8960..73bb672 100644
--- a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed
+++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.fixed
@@ -2,7 +2,7 @@
 #![allow(unused_variables, dead_code)]
 
 trait Trait {
-    fn foo() where Self: Other, Self: Sized, { }
+    fn foo(&self) where Self: Other, Self: Sized, { }
     fn bar(self: &Self) {} //~ ERROR invalid `self` parameter type
 }
 
diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr
index 6466a76..a2caf84 100644
--- a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr
+++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr
@@ -1,17 +1,23 @@
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:11
    |
+LL | fn bar(x: &dyn Trait) {}
+   |           ^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/object-unsafe-trait-should-use-where-sized.rs:5:8
+   |
 LL | trait Trait {
    |       ----- this trait cannot be made into an object...
 LL |     fn foo() where Self: Other, { }
-   |        --- ...because associated function `foo` has no `self` parameter
+   |        ^^^ ...because associated function `foo` has no `self` parameter
 LL |     fn bar(self: ()) {}
-   |                  -- ...because method `bar`'s `self` parameter cannot be dispatched on
-...
-LL | fn bar(x: &dyn Trait) {}
-   |           ^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |                  ^^ ...because method `bar`'s `self` parameter cannot be dispatched on
+help: consider turning `foo` into a method by giving it a `&self` argument
    |
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn foo(&self) where Self: Other, { }
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() where Self: Other, Self: Sized, { }
    |                               ^^^^^^^^^^^^^
diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.stderr b/src/test/ui/suggestions/suggest-remove-refs-1.stderr
index 0dd1b2a..4aa0ad2 100644
--- a/src/test/ui/suggestions/suggest-remove-refs-1.stderr
+++ b/src/test/ui/suggestions/suggest-remove-refs-1.stderr
@@ -8,6 +8,7 @@
    |                   help: consider removing the leading `&`-reference
    |
    = help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required by `into_iter`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/suggest-remove-refs-2.stderr b/src/test/ui/suggestions/suggest-remove-refs-2.stderr
index 5c2efdb..15c4b7f 100644
--- a/src/test/ui/suggestions/suggest-remove-refs-2.stderr
+++ b/src/test/ui/suggestions/suggest-remove-refs-2.stderr
@@ -8,6 +8,7 @@
    |                   help: consider removing 5 leading `&`-references
    |
    = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required by `into_iter`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/suggest-remove-refs-3.stderr b/src/test/ui/suggestions/suggest-remove-refs-3.stderr
index c7fbd3d..0bd6d95 100644
--- a/src/test/ui/suggestions/suggest-remove-refs-3.stderr
+++ b/src/test/ui/suggestions/suggest-remove-refs-3.stderr
@@ -12,6 +12,7 @@
    | |_____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
+   = note: required because of the requirements on the impl of `IntoIterator` for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required by `into_iter`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr
index f717cc7..b391cd4 100644
--- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr
+++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr
@@ -5,7 +5,7 @@
    |                   ^
    |                   |
    |                   expected `f64`, found `f32`
-   |                   help: you can convert an `f32` to `f64`: `r: r.into()`
+   |                   help: you can convert an `f32` to an `f64`: `r: r.into()`
 
 error[E0308]: mismatched types
   --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:22
@@ -14,7 +14,7 @@
    |                      ^
    |                      |
    |                      expected `f64`, found `f32`
-   |                      help: you can convert an `f32` to `f64`: `g: g.into()`
+   |                      help: you can convert an `f32` to an `f64`: `g: g.into()`
 
 error[E0560]: struct `RGB` has no field named `c`
   --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:25
diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr
index 7521c25..61ea852 100644
--- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr
+++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr
@@ -5,7 +5,7 @@
    |                   ^
    |                   |
    |                   expected `f64`, found `f32`
-   |                   help: you can convert an `f32` to `f64`: `r: r.into()`
+   |                   help: you can convert an `f32` to an `f64`: `r: r.into()`
 
 error[E0308]: mismatched types
   --> $DIR/type-mismatch-struct-field-shorthand.rs:8:22
@@ -14,7 +14,7 @@
    |                      ^
    |                      |
    |                      expected `f64`, found `f32`
-   |                      help: you can convert an `f32` to `f64`: `g: g.into()`
+   |                      help: you can convert an `f32` to an `f64`: `g: g.into()`
 
 error[E0308]: mismatched types
   --> $DIR/type-mismatch-struct-field-shorthand.rs:8:25
@@ -23,7 +23,7 @@
    |                         ^
    |                         |
    |                         expected `f64`, found `f32`
-   |                         help: you can convert an `f32` to `f64`: `b: b.into()`
+   |                         help: you can convert an `f32` to an `f64`: `b: b.into()`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/symbol-names/const-generics-demangling.rs b/src/test/ui/symbol-names/const-generics-demangling.rs
new file mode 100644
index 0000000..e002124
--- /dev/null
+++ b/src/test/ui/symbol-names/const-generics-demangling.rs
@@ -0,0 +1,38 @@
+// build-fail
+// compile-flags: -Z symbol-mangling-version=v0
+
+#![feature(min_const_generics, rustc_attrs)]
+
+pub struct Unsigned<const F: u8>;
+
+#[rustc_symbol_name]
+//~^ ERROR symbol-name(_RMCs4fqI2P2rA04_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+//~| ERROR demangling(<const_generics_demangling[317d481089b8c8fe]::Unsigned<11: u8>>)
+//~| ERROR demangling-alt(<const_generics_demangling::Unsigned<11>>)
+impl Unsigned<11> {}
+
+pub struct Signed<const F: i16>;
+
+#[rustc_symbol_name]
+//~^ ERROR symbol-name(_RMs_Cs4fqI2P2rA04_25const_generics_demanglingINtB2_6SignedKsn98_E)
+//~| ERROR demangling(<const_generics_demangling[317d481089b8c8fe]::Signed<-152: i16>>)
+//~| ERROR demangling-alt(<const_generics_demangling::Signed<-152>>)
+impl Signed<-152> {}
+
+pub struct Bool<const F: bool>;
+
+#[rustc_symbol_name]
+//~^ ERROR symbol-name(_RMs0_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4BoolKb1_E)
+//~| ERROR demangling(<const_generics_demangling[317d481089b8c8fe]::Bool<true: bool>>)
+//~| ERROR demangling-alt(<const_generics_demangling::Bool<true>>)
+impl Bool<true> {}
+
+pub struct Char<const F: char>;
+
+#[rustc_symbol_name]
+//~^ ERROR symbol-name(_RMs1_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4CharKc2202_E)
+//~| ERROR demangling(<const_generics_demangling[317d481089b8c8fe]::Char<'∂': char>>)
+//~| ERROR demangling-alt(<const_generics_demangling::Char<'∂'>>)
+impl Char<'∂'> {}
+
+fn main() {}
diff --git a/src/test/ui/symbol-names/const-generics-demangling.stderr b/src/test/ui/symbol-names/const-generics-demangling.stderr
new file mode 100644
index 0000000..022b318
--- /dev/null
+++ b/src/test/ui/symbol-names/const-generics-demangling.stderr
@@ -0,0 +1,74 @@
+error: symbol-name(_RMCs4fqI2P2rA04_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+  --> $DIR/const-generics-demangling.rs:8:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<const_generics_demangling[317d481089b8c8fe]::Unsigned<11: u8>>)
+  --> $DIR/const-generics-demangling.rs:8:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<const_generics_demangling::Unsigned<11>>)
+  --> $DIR/const-generics-demangling.rs:8:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs_Cs4fqI2P2rA04_25const_generics_demanglingINtB2_6SignedKsn98_E)
+  --> $DIR/const-generics-demangling.rs:16:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<const_generics_demangling[317d481089b8c8fe]::Signed<-152: i16>>)
+  --> $DIR/const-generics-demangling.rs:16:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<const_generics_demangling::Signed<-152>>)
+  --> $DIR/const-generics-demangling.rs:16:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs0_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4BoolKb1_E)
+  --> $DIR/const-generics-demangling.rs:24:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<const_generics_demangling[317d481089b8c8fe]::Bool<true: bool>>)
+  --> $DIR/const-generics-demangling.rs:24:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<const_generics_demangling::Bool<true>>)
+  --> $DIR/const-generics-demangling.rs:24:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs1_Cs4fqI2P2rA04_25const_generics_demanglingINtB3_4CharKc2202_E)
+  --> $DIR/const-generics-demangling.rs:32:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<const_generics_demangling[317d481089b8c8fe]::Char<'∂': char>>)
+  --> $DIR/const-generics-demangling.rs:32:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<const_generics_demangling::Char<'∂'>>)
+  --> $DIR/const-generics-demangling.rs:32:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/ui/symbol-names/const-generics.rs b/src/test/ui/symbol-names/const-generics.rs
new file mode 100644
index 0000000..ad87000
--- /dev/null
+++ b/src/test/ui/symbol-names/const-generics.rs
@@ -0,0 +1,87 @@
+// check-pass
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
+    //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+
+    #![feature(min_const_generics)]
+
+    // `char`
+    pub struct Char<const F: char>;
+
+    impl Char<'A'> {
+        pub fn foo() {}
+    }
+
+    impl<const F: char> Char<F> {
+        pub fn bar() {}
+    }
+
+    // `i8`
+    pub struct I8<const F: i8>;
+
+    impl I8<{std::i8::MIN}> {
+        pub fn foo() {}
+    }
+
+    impl I8<{std::i8::MAX}> {
+        pub fn foo() {}
+    }
+
+    impl<const F: i8> I8<F> {
+        pub fn bar() {}
+    }
+
+    // `i16`
+    pub struct I16<const F: i16>;
+
+    impl I16<{std::i16::MIN}> {
+        pub fn foo() {}
+    }
+
+    impl<const F: i16> I16<F> {
+        pub fn bar() {}
+    }
+
+    // `i32`
+    pub struct I32<const F: i32>;
+
+    impl I32<{std::i32::MIN}> {
+        pub fn foo() {}
+    }
+
+    impl<const F: i32> I32<F> {
+        pub fn bar() {}
+    }
+
+    // `i64`
+    pub struct I64<const F: i64>;
+
+    impl I64<{std::i64::MIN}> {
+        pub fn foo() {}
+    }
+
+    impl<const F: i64> I64<F> {
+        pub fn bar() {}
+    }
+
+    // `i128`
+    pub struct I128<const F: i128>;
+
+    impl I128<{std::i128::MIN}> {
+        pub fn foo() {}
+    }
+
+    impl<const F: i128> I128<F> {
+        pub fn bar() {}
+    }
+
+    // `isize`
+    pub struct ISize<const F: isize>;
+
+    impl ISize<3> {
+        pub fn foo() {}
+    }
+
+    impl<const F: isize> ISize<F> {
+        pub fn bar() {}
+    }
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index e4c20cd..c866f9b 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -64,7 +64,7 @@
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method)
+error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:71:13
    |
 LL |             #[rustc_def_path]
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index 1d86abd..1ada54c 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -69,8 +69,8 @@
                 //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
                 //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
             #[rustc_def_path]
-            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method)
-               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method)
+            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
+               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
             fn method(&self) {}
         }
     };
diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr
index 01d047d..db5eda0 100644
--- a/src/test/ui/symbol-names/impl1.v0.stderr
+++ b/src/test/ui/symbol-names/impl1.v0.stderr
@@ -64,7 +64,7 @@
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method)
+error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:71:13
    |
 LL |             #[rustc_def_path]
diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr
new file mode 100644
index 0000000..5f822f6
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr
@@ -0,0 +1,20 @@
+error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs
new file mode 100644
index 0000000..ce31516
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-75326.rs
@@ -0,0 +1,58 @@
+// build-fail
+// ignore-tidy-linelength
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy
+//[v0]compile-flags: -Z symbol-mangling-version=v0
+//[legacy]normalize-stderr-32bit: "h[\d\w]+" -> "SYMBOL_HASH"
+//[legacy]normalize-stderr-64bit: "h[\d\w]+" -> "SYMBOL_HASH"
+
+#![feature(rustc_attrs)]
+
+pub(crate) struct Foo<I, E>(I, E);
+
+pub trait Iterator2 {
+    type Item;
+
+    fn next(&mut self) -> Option<Self::Item>;
+
+    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
+    where
+        Self: Sized,
+        P: FnMut(&Self::Item) -> bool,
+    {
+        unimplemented!()
+    }
+}
+
+struct Bar;
+
+impl Iterator2 for Bar {
+    type Item = (u32, u16);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        unimplemented!()
+    }
+}
+
+impl<I, T, E> Iterator2 for Foo<I, E>
+where
+    I: Iterator2<Item = (T, E)>,
+{
+    type Item = T;
+
+    #[rustc_symbol_name]
+    //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
+    //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
+    //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
+    //[v0]~^^^^  ERROR symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+    //[v0]~|     ERROR demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next)
+    //[v0]~|     ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
+    fn next(&mut self) -> Option<Self::Item> {
+        self.find(|_| true)
+    }
+}
+
+fn main() {
+    let mut a = Foo(Bar, 1u16);
+    let _ = a.next();
+}
diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr
new file mode 100644
index 0000000..59bdfa8
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-75326.v0.stderr
@@ -0,0 +1,20 @@
+error: symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/symbol-names/issue-76365.rs b/src/test/ui/symbol-names/issue-76365.rs
new file mode 100644
index 0000000..61ba255
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-76365.rs
@@ -0,0 +1,18 @@
+// check-pass
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
+    //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+
+#![feature(min_const_generics)]
+
+pub struct Bar<const F: bool>;
+
+impl Bar<true> {
+    pub fn foo() {}
+}
+
+impl<const F: bool> Bar<F> {
+    pub fn bar() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr
index 69f8ffa..cff0991 100644
--- a/src/test/ui/tail-typeck.stderr
+++ b/src/test/ui/tail-typeck.stderr
@@ -6,7 +6,7 @@
    |           |
    |           expected `isize` because of return type
    |
-help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit
    |
 LL | fn f() -> isize { return g().try_into().unwrap(); }
    |                          ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.rs b/src/test/ui/traits/assoc_type_bound_with_struct.rs
new file mode 100644
index 0000000..c66009f
--- /dev/null
+++ b/src/test/ui/traits/assoc_type_bound_with_struct.rs
@@ -0,0 +1,19 @@
+trait Bar {
+    type Baz;
+}
+
+struct Foo<T> where T: Bar, <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+    t: T,
+}
+
+struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+    t: &'a T,
+}
+
+fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+}
+
+fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.stderr b/src/test/ui/traits/assoc_type_bound_with_struct.stderr
new file mode 100644
index 0000000..7cf872e
--- /dev/null
+++ b/src/test/ui/traits/assoc_type_bound_with_struct.stderr
@@ -0,0 +1,83 @@
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:5:46
+   |
+LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: String {
+   |                                              ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | struct Foo<T> where T: Bar, T: Bar<Baz = String> {
+   |                             ^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: ToString {
+   |                                              ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:9:54
+   |
+LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String {
+   |                                                      ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | struct Qux<'a, T> where T: Bar, &'a T: Bar<Baz = String> {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: ToString {
+   |                                                      ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:13:45
+   |
+LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String {
+   |                                             ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | fn foo<T: Bar>(_: T) where T: Bar<Baz = String> {
+   |                            ^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: ToString {
+   |                                             ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:16:57
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String {
+   |                                                         ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where &'a T: Bar<Baz = String> {
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: ToString {
+   |                                                         ^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0404`.
diff --git a/src/test/ui/traits/check-trait-object-bounds-1.rs b/src/test/ui/traits/check-trait-object-bounds-1.rs
new file mode 100644
index 0000000..b1f124c
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-1.rs
@@ -0,0 +1,14 @@
+// Check that we validate associated type bounds for trait objects
+
+trait X {
+    type Y: Clone;
+}
+
+fn f<T: X + ?Sized>() {
+    None::<T::Y>.clone();
+}
+
+fn main() {
+    f::<dyn X<Y = str>>();
+    //~^ ERROR the trait bound `str: Clone` is not satisfied
+}
diff --git a/src/test/ui/traits/check-trait-object-bounds-1.stderr b/src/test/ui/traits/check-trait-object-bounds-1.stderr
new file mode 100644
index 0000000..170ed6e
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-1.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `str: Clone` is not satisfied
+  --> $DIR/check-trait-object-bounds-1.rs:12:5
+   |
+LL | fn f<T: X + ?Sized>() {
+   |         - required by this bound in `f`
+...
+LL |     f::<dyn X<Y = str>>();
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/check-trait-object-bounds-2-ok.rs b/src/test/ui/traits/check-trait-object-bounds-2-ok.rs
new file mode 100644
index 0000000..1422dda
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-2-ok.rs
@@ -0,0 +1,15 @@
+// Make sure that we're handling bound lifetimes correctly when validating trait
+// bounds.
+// run-pass
+
+trait X<'a> {
+    type F: FnOnce(&i32) -> &'a i32;
+}
+
+fn f<T: for<'r> X<'r> + ?Sized>() {
+    None::<T::F>.map(|f| f(&0));
+}
+
+fn main() {
+    f::<dyn for<'x> X<'x, F = fn(&i32) -> &'x i32>>();
+}
diff --git a/src/test/ui/traits/check-trait-object-bounds-2.rs b/src/test/ui/traits/check-trait-object-bounds-2.rs
new file mode 100644
index 0000000..eb2fb6e
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-2.rs
@@ -0,0 +1,15 @@
+// Check that we validate associated type bounds for trait objects when they
+// have bound lifetimes
+
+trait X<'a> {
+    type F: FnOnce(&i32) -> &'a i32;
+}
+
+fn f<T: for<'r> X<'r> + ?Sized>() {
+    None::<T::F>.map(|f| f(&0));
+}
+
+fn main() {
+    f::<dyn for<'x> X<'x, F = i32>>();
+    //~^ expected a `FnOnce<(&i32,)>` closure, found `i32`
+}
diff --git a/src/test/ui/traits/check-trait-object-bounds-2.stderr b/src/test/ui/traits/check-trait-object-bounds-2.stderr
new file mode 100644
index 0000000..04e2348
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-2.stderr
@@ -0,0 +1,14 @@
+error[E0277]: expected a `FnOnce<(&i32,)>` closure, found `i32`
+  --> $DIR/check-trait-object-bounds-2.rs:13:5
+   |
+LL | fn f<T: for<'r> X<'r> + ?Sized>() {
+   |         ------------- required by this bound in `f`
+...
+LL |     f::<dyn for<'x> X<'x, F = i32>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&i32,)>` closure, found `i32`
+   |
+   = help: the trait `for<'r> FnOnce<(&'r i32,)>` is not implemented for `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/check-trait-object-bounds-3.rs b/src/test/ui/traits/check-trait-object-bounds-3.rs
new file mode 100644
index 0000000..ba04fd9
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-3.rs
@@ -0,0 +1,20 @@
+// Check that we validate associated type bounds for trait objects
+
+trait X<'a> {
+    type Y: Into<&'static str> + From<&'a str>;
+}
+
+fn f<'a, T: X<'a> + ?Sized>(s: &'a str) -> &'static str {
+    T::Y::from(s).into()
+}
+
+pub fn main() {
+    let z;
+    {
+        let s = String::from("abcdef");
+        z = f::<dyn X<Y = &str>>(&s);
+        //~^ ERROR `s` does not live long enough
+    }
+
+    println!("{}", z)
+}
diff --git a/src/test/ui/traits/check-trait-object-bounds-3.stderr b/src/test/ui/traits/check-trait-object-bounds-3.stderr
new file mode 100644
index 0000000..ade552c
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-3.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `s` does not live long enough
+  --> $DIR/check-trait-object-bounds-3.rs:15:34
+   |
+LL |         z = f::<dyn X<Y = &str>>(&s);
+   |             ---------------------^^-
+   |             |                    |
+   |             |                    borrowed value does not live long enough
+   |             argument requires that `s` is borrowed for `'static`
+LL |
+LL |     }
+   |     - `s` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/traits/check-trait-object-bounds-4.rs b/src/test/ui/traits/check-trait-object-bounds-4.rs
new file mode 100644
index 0000000..e9ca156
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-4.rs
@@ -0,0 +1,17 @@
+// Check that we validate associated type bounds on super traits for trait
+// objects
+
+trait Super {
+    type Y: Clone;
+}
+
+trait X: Super {}
+
+fn f<T: X + ?Sized>() {
+    None::<T::Y>.clone();
+}
+
+fn main() {
+    f::<dyn X<Y = str>>();
+    //~^ ERROR the trait bound `str: Clone` is not satisfied
+}
diff --git a/src/test/ui/traits/check-trait-object-bounds-4.stderr b/src/test/ui/traits/check-trait-object-bounds-4.stderr
new file mode 100644
index 0000000..fc9f31c
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-4.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `str: Clone` is not satisfied
+  --> $DIR/check-trait-object-bounds-4.rs:15:5
+   |
+LL | fn f<T: X + ?Sized>() {
+   |         - required by this bound in `f`
+...
+LL |     f::<dyn X<Y = str>>();
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/check-trait-object-bounds-5.rs b/src/test/ui/traits/check-trait-object-bounds-5.rs
new file mode 100644
index 0000000..7d733ad
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-5.rs
@@ -0,0 +1,27 @@
+// Check that we validate associated type bounds on super traits for trait
+// objects
+
+trait Is {
+    type T;
+}
+
+impl<U> Is for U {
+    type T = U;
+}
+
+trait Super {
+    type V;
+}
+
+trait Obj: Super {
+    type U: Is<T = Self::V>;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32, V = i64>) {
+    is_obj(x)
+    //~^ type mismatch resolving `<i32 as Is>::T == i64`
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/check-trait-object-bounds-5.stderr b/src/test/ui/traits/check-trait-object-bounds-5.stderr
new file mode 100644
index 0000000..bd2b789
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-5.stderr
@@ -0,0 +1,12 @@
+error[E0271]: type mismatch resolving `<i32 as Is>::T == i64`
+  --> $DIR/check-trait-object-bounds-5.rs:23:5
+   |
+LL | fn is_obj<T: ?Sized + Obj>(_: &T) {}
+   |                       --- required by this bound in `is_obj`
+...
+LL |     is_obj(x)
+   |     ^^^^^^ expected `i64`, found `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/traits/check-trait-object-bounds-6.rs b/src/test/ui/traits/check-trait-object-bounds-6.rs
new file mode 100644
index 0000000..cb196d6
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-6.rs
@@ -0,0 +1,24 @@
+// Check that we validate associated type bounds on super traits for trait
+// objects
+
+trait Is {
+    type T;
+}
+
+impl<U> Is for U {
+    type T = U;
+}
+
+trait Obj {
+    type U: Is<T = Self::V>;
+    type V;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32, V = i64>) {
+    is_obj(x)
+    //~^ ERROR type mismatch resolving `<i32 as Is>::T == i64`
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/check-trait-object-bounds-6.stderr b/src/test/ui/traits/check-trait-object-bounds-6.stderr
new file mode 100644
index 0000000..ea1fdaf
--- /dev/null
+++ b/src/test/ui/traits/check-trait-object-bounds-6.stderr
@@ -0,0 +1,12 @@
+error[E0271]: type mismatch resolving `<i32 as Is>::T == i64`
+  --> $DIR/check-trait-object-bounds-6.rs:20:5
+   |
+LL | fn is_obj<T: ?Sized + Obj>(_: &T) {}
+   |                       --- required by this bound in `is_obj`
+...
+LL |     is_obj(x)
+   |     ^^^^^^ expected `i64`, found `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/traits/cycle-cache-err-60010.rs b/src/test/ui/traits/cycle-cache-err-60010.rs
index cbddef0..98bfcb8 100644
--- a/src/test/ui/traits/cycle-cache-err-60010.rs
+++ b/src/test/ui/traits/cycle-cache-err-60010.rs
@@ -24,11 +24,13 @@
     _storage: Box<DB::Storage>,
 }
 struct SalsaStorage {
-    _parse: <ParseQuery as Query<RootDatabase>>::Data, //~ ERROR overflow
+    _parse: <ParseQuery as Query<RootDatabase>>::Data,
 }
 
 impl Database for RootDatabase {
-    type Storage = SalsaStorage; //~ ERROR overflow
+    // This would also be an error if we didn't abort compilation on the error
+    // above.
+    type Storage = SalsaStorage;
 }
 impl HasQueryGroup for RootDatabase {}
 impl<DB> Query<DB> for ParseQuery
@@ -65,6 +67,7 @@
     // we used to fail to report an error here because we got the
     // caching wrong.
     SourceDatabase::parse(db);
+    //~^ ERROR overflow
     22
 }
 
diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr
index 25b1f42..b2702d9 100644
--- a/src/test/ui/traits/cycle-cache-err-60010.stderr
+++ b/src/test/ui/traits/cycle-cache-err-60010.stderr
@@ -1,27 +1,19 @@
-error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
-  --> $DIR/cycle-cache-err-60010.rs:27:13
+error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe`
+  --> $DIR/cycle-cache-err-60010.rs:69:5
    |
-LL |     _parse: <ParseQuery as Query<RootDatabase>>::Data,
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
-
-error[E0275]: overflow evaluating the requirement `Runtime<RootDatabase>: RefUnwindSafe`
-  --> $DIR/cycle-cache-err-60010.rs:31:20
-   |
-LL | trait Database {
-   |       -------- required by a bound in this
-LL |     type Storage;
-   |     ------------- required by this bound in `Database`
+LL |     fn parse(&self) {
+   |     --------------- required by `SourceDatabase::parse`
 ...
-LL |     type Storage = SalsaStorage;
-   |                    ^^^^^^^^^^^^
+LL |     SourceDatabase::parse(db);
+   |     ^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: required because it appears within the type `*const SalsaStorage`
+   = note: required because it appears within the type `Unique<SalsaStorage>`
+   = note: required because it appears within the type `Box<SalsaStorage>`
+   = note: required because it appears within the type `Runtime<RootDatabase>`
    = note: required because it appears within the type `RootDatabase`
    = note: required because of the requirements on the impl of `SourceDatabase` for `RootDatabase`
-   = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
-   = note: required because it appears within the type `SalsaStorage`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/traits/issue-70944.rs b/src/test/ui/traits/issue-70944.rs
new file mode 100644
index 0000000..3286de9
--- /dev/null
+++ b/src/test/ui/traits/issue-70944.rs
@@ -0,0 +1,23 @@
+// check-pass
+// Regression test of #70944, should compile fine.
+
+use std::ops::Index;
+
+pub struct KeyA;
+pub struct KeyB;
+pub struct KeyC;
+
+pub trait Foo: Index<KeyA> + Index<KeyB> + Index<KeyC> {}
+pub trait FooBuilder {
+    type Inner: Foo;
+    fn inner(&self) -> &Self::Inner;
+}
+
+pub fn do_stuff(foo: &impl FooBuilder) {
+    let inner = foo.inner();
+    &inner[KeyA];
+    &inner[KeyB];
+    &inner[KeyC];
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-72410.stderr b/src/test/ui/traits/issue-72410.stderr
index 1db2320..c91d1db 100644
--- a/src/test/ui/traits/issue-72410.stderr
+++ b/src/test/ui/traits/issue-72410.stderr
@@ -1,14 +1,21 @@
 error[E0038]: the trait `Bar` cannot be made into an object
   --> $DIR/issue-72410.rs:14:19
    |
+LL |     where for<'a> &'a mut [dyn Bar]: ;
+   |                   ^^^^^^^^^^^^^^^^^ `Bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-72410.rs:13:8
+   |
 LL | pub trait Bar {
    |           --- this trait cannot be made into an object...
 LL |     fn map()
-   |        --- ...because associated function `map` has no `self` parameter
-LL |     where for<'a> &'a mut [dyn Bar]: ;
-   |                   ^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
+   |        ^^^ ...because associated function `map` has no `self` parameter
+help: consider turning `map` into a method by giving it a `&self` argument
    |
-help: consider turning `map` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn map(&self)
+   |            ^^^^^
+help: alternatively, consider constraining `map` so it does not apply to trait objects
    |
 LL |     where for<'a> &'a mut [dyn Bar]:, Self: Sized ;
    |                                     ^^^^^^^^^^^^^
diff --git a/src/test/ui/traits/issue-75627.rs b/src/test/ui/traits/issue-75627.rs
new file mode 100644
index 0000000..93a2ec1
--- /dev/null
+++ b/src/test/ui/traits/issue-75627.rs
@@ -0,0 +1,6 @@
+struct Foo<T>(T, *const ());
+
+unsafe impl Send for Foo<T> {}
+//~^ ERROR cannot find type
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-75627.stderr b/src/test/ui/traits/issue-75627.stderr
new file mode 100644
index 0000000..92d9ac0
--- /dev/null
+++ b/src/test/ui/traits/issue-75627.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/issue-75627.rs:3:26
+   |
+LL | unsafe impl Send for Foo<T> {}
+   |                          ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/traits/issue-77982.rs b/src/test/ui/traits/issue-77982.rs
new file mode 100644
index 0000000..03d4fe2
--- /dev/null
+++ b/src/test/ui/traits/issue-77982.rs
@@ -0,0 +1,40 @@
+use std::collections::HashMap;
+
+fn what() {
+    let descr = String::new();
+    let mut opts = HashMap::<String, ()>::new();
+    let opt = String::new();
+
+    opts.get(opt.as_ref()); //~ ERROR type annotations needed
+}
+
+fn main() {
+    let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
+    //~^ ERROR type annotations needed
+}
+
+trait Foo<'a, T: ?Sized> {
+    fn foo(&self) -> Box<T> {
+        todo!()
+    }
+}
+
+trait Bar<'a, T: ?Sized> {
+    fn bar(&self) -> Box<T> {
+        todo!()
+    }
+}
+
+impl Foo<'static, u32> for () {}
+impl<'a> Foo<'a, i16> for () {}
+
+impl<'a> Bar<'static, u32> for &'a () {}
+impl<'a> Bar<'a, i16> for &'a () {}
+
+fn foo() {
+    let _ = ().foo(); //~ ERROR type annotations needed
+}
+
+fn bar() {
+    let _ = (&()).bar(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr
new file mode 100644
index 0000000..d788f18
--- /dev/null
+++ b/src/test/ui/traits/issue-77982.stderr
@@ -0,0 +1,44 @@
+error[E0283]: type annotations needed
+  --> $DIR/issue-77982.rs:8:10
+   |
+LL |     opts.get(opt.as_ref());
+   |          ^^^ ------------ this method call resolves to `&T`
+   |          |
+   |          cannot infer type for type parameter `Q` declared on the associated function `get`
+   |
+   = note: cannot satisfy `String: Borrow<_>`
+
+error[E0283]: type annotations needed
+  --> $DIR/issue-77982.rs:12:44
+   |
+LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
+   |                                            ^^^^^^^^^ ----------- this method call resolves to `T`
+   |                                            |
+   |                                            cannot infer type for type parameter `T` declared on the trait `From`
+   |
+   = note: cannot satisfy `u32: From<_>`
+   = note: required by `from`
+
+error[E0283]: type annotations needed for `Box<T>`
+  --> $DIR/issue-77982.rs:35:16
+   |
+LL |     let _ = ().foo();
+   |         -      ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
+   |         |
+   |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+   |
+   = note: cannot satisfy `(): Foo<'_, _>`
+
+error[E0283]: type annotations needed for `Box<T>`
+  --> $DIR/issue-77982.rs:39:19
+   |
+LL |     let _ = (&()).bar();
+   |         -         ^^^ cannot infer type for type parameter `T` declared on the trait `Bar`
+   |         |
+   |         consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+   |
+   = note: cannot satisfy `&(): Bar<'_, _>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.stderr b/src/test/ui/traits/negative-impls/negative-default-impls.stderr
index 50e7437..ceb8655 100644
--- a/src/test/ui/traits/negative-impls/negative-default-impls.stderr
+++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0750]: negative impls cannot be default impls
   --> $DIR/negative-default-impls.rs:9:1
diff --git a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr
index 8b536de..9a84614 100644
--- a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr
+++ b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr
index 89ef15e..77b4373 100644
--- a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr
+++ b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
   --> $DIR/negative-specializes-positive-item.rs:11:1
diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr
index e45d5a2..e5dc81b 100644
--- a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr
+++ b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
   --> $DIR/negative-specializes-positive.rs:7:1
diff --git a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr
index 49c16d4..c091bc8 100644
--- a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr
+++ b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`:
   --> $DIR/positive-specializes-negative.rs:7:1
diff --git a/src/test/ui/traits/normalize-super-trait.rs b/src/test/ui/traits/normalize-super-trait.rs
new file mode 100644
index 0000000..021a93e
--- /dev/null
+++ b/src/test/ui/traits/normalize-super-trait.rs
@@ -0,0 +1,37 @@
+// Regression test for #77653
+// When monomorphizing `f` we need to prove `dyn Derived<()>: Base<()>`. This
+// requires us to normalize the `Base<<() as Proj>::S>` to `Base<()>` when
+// comparing the supertrait `Derived<()>` to the expected trait.
+
+// build-pass
+
+trait Proj {
+    type S;
+}
+
+impl Proj for () {
+    type S = ();
+}
+
+impl Proj for i32 {
+    type S = i32;
+}
+
+trait Base<T> {
+    fn is_base(&self);
+}
+
+trait Derived<B: Proj>: Base<B::S> + Base<()> {
+    fn is_derived(&self);
+}
+
+fn f<P: Proj>(obj: &dyn Derived<P>) {
+    obj.is_derived();
+    Base::<P::S>::is_base(obj);
+    Base::<()>::is_base(obj);
+}
+
+fn main() {
+    let x: fn(_) = f::<()>;
+    let x: fn(_) = f::<i32>;
+}
diff --git a/src/test/ui/traits/trait-alias/issue-75983.rs b/src/test/ui/traits/trait-alias/issue-75983.rs
new file mode 100644
index 0000000..f9a7f36
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/issue-75983.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+#![feature(trait_alias)]
+
+struct Bar;
+trait Foo {}
+impl Foo for Bar {}
+
+trait Baz = Foo where Bar: Foo;
+
+fn new() -> impl Baz {
+    Bar
+}
+
+fn main() {
+    let _ = new();
+}
diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
index 1f54e03..1118a75 100644
--- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
@@ -2,12 +2,13 @@
   --> $DIR/trait-alias-object-fail.rs:7:13
    |
 LL |     let _: &dyn EqAlias = &123;
-   |             ^^^^^^^^^^^ the trait `Eq` cannot be made into an object
-   | 
-  ::: $SRC_DIR/core/src/cmp.rs:LL:COL
+   |             ^^^^^^^^^^^ `Eq` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    |
 LL | pub trait Eq: PartialEq<Self> {
-   |               --------------- the trait cannot be made into an object because it uses `Self` as a type parameter in this
+   |               ^^^^^^^^^^^^^^^ the trait cannot be made into an object because it uses `Self` as a type parameter
 
 error[E0191]: the value of the associated type `Item` (from trait `Iterator`) must be specified
   --> $DIR/trait-alias-object-fail.rs:9:17
diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.rs b/src/test/ui/traits/trait-bounds-not-on-struct.rs
index c6e93e7..8633e9d 100644
--- a/src/test/ui/traits/trait-bounds-not-on-struct.rs
+++ b/src/test/ui/traits/trait-bounds-not-on-struct.rs
@@ -1,9 +1,38 @@
+// We don't need those errors. Ideally we would silence them, but to do so we need to move the
+// lint from being an early-lint during parsing to a late-lint, because it needs to be aware of
+// the types involved.
 #![allow(bare_trait_objects)]
 
 struct Foo;
 
 fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
 
-type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
+type TypeAlias<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
 
-fn main() { }
+struct A;
+fn a() -> A + 'static { //~ ERROR expected trait, found
+    A
+}
+fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { //~ ERROR expected trait, found
+    panic!()
+}
+fn c() -> 'static + A { //~ ERROR expected trait, found
+    A
+}
+fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { //~ ERROR expected trait, found
+    panic!()
+}
+fn e() -> 'static + A + 'static { //~ ERROR expected trait, found
+//~^ ERROR only a single explicit lifetime bound is permitted
+    A
+}
+fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { //~ ERROR expected trait, found
+//~^ ERROR only a single explicit lifetime bound is permitted
+    panic!()
+}
+struct Traitor;
+trait Trait {}
+fn g() -> Traitor + 'static { //~ ERROR expected trait, found struct `Traitor`
+    A
+}
+fn main() {}
diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.stderr b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
index a649a4e..0f97e3b 100644
--- a/src/test/ui/traits/trait-bounds-not-on-struct.stderr
+++ b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
@@ -1,15 +1,168 @@
+error[E0226]: only a single explicit lifetime bound is permitted
+  --> $DIR/trait-bounds-not-on-struct.rs:25:25
+   |
+LL | fn e() -> 'static + A + 'static {
+   |                         ^^^^^^^
+
+error[E0226]: only a single explicit lifetime bound is permitted
+  --> $DIR/trait-bounds-not-on-struct.rs:29:53
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                                     ^^
+
 error[E0404]: expected trait, found struct `Foo`
-  --> $DIR/trait-bounds-not-on-struct.rs:5:16
+  --> $DIR/trait-bounds-not-on-struct.rs:8:16
    |
 LL | fn foo(_x: Box<Foo + Send>) { }
    |                ^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:8:22
+   |
+LL | fn foo(_x: Box<Foo + Send>) { }
+   |                ---   ^^^^ ...because of this bound
+   |                |
+   |                expected this type to be a trait...
 
 error[E0404]: expected trait, found struct `Vec`
-  --> $DIR/trait-bounds-not-on-struct.rs:7:21
+  --> $DIR/trait-bounds-not-on-struct.rs:10:29
    |
-LL | type A<T> = Box<dyn Vec<T>>;
-   |                     ^^^^^^ not a trait
+LL | type TypeAlias<T> = Box<dyn Vec<T>>;
+   |                             ^^^^^^ not a trait
 
-error: aborting due to 2 previous errors
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:13:11
+   |
+LL | fn a() -> A + 'static {
+   |           ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:13:15
+   |
+LL | fn a() -> A + 'static {
+   |           -   ^^^^^^^ ...because of this bound
+   |           |
+   |           expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn a() -> A {
+   |           --
 
-For more information about this error, try `rustc --explain E0404`.
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:16:34
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
+   |                                  ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:16:48
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
+   |                                  -----------   ^^ ...because of this bound
+   |                                  |
+   |                                  expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                            --
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:19:21
+   |
+LL | fn c() -> 'static + A {
+   |                     ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:19:11
+   |
+LL | fn c() -> 'static + A {
+   |           ^^^^^^^   - expected this type to be a trait...
+   |           |
+   |           ...because of this bound
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn c() -> A {
+   |          --
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:22:39
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
+   |                                       ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:22:34
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
+   |                                  ^^   ----------- expected this type to be a trait...
+   |                                  |
+   |                                  ...because of this bound
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                 --
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:25:21
+   |
+LL | fn e() -> 'static + A + 'static {
+   |                     ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:25:11
+   |
+LL | fn e() -> 'static + A + 'static {
+   |           ^^^^^^^   -   ^^^^^^^ ...because of these bounds
+   |                     |
+   |                     expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn e() -> A {
+   |          ---
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:29:39
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                       ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:29:34
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                  ^^   -----------   ^^ ...because of these bounds
+   |                                       |
+   |                                       expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                 --         --
+
+error[E0404]: expected trait, found struct `Traitor`
+  --> $DIR/trait-bounds-not-on-struct.rs:35:11
+   |
+LL | trait Trait {}
+   | ----------- similarly named trait `Trait` defined here
+LL | fn g() -> Traitor + 'static {
+   |           ^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:35:21
+   |
+LL | fn g() -> Traitor + 'static {
+   |           -------   ^^^^^^^ ...because of this bound
+   |           |
+   |           expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn g() -> Traitor {
+   |                 --
+help: a trait with a similar name exists
+   |
+LL | fn g() -> Trait + 'static {
+   |           ^^^^^
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0226, E0404.
+For more information about an error, try `rustc --explain E0226`.
diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr
index 3be4f11..4d97d93 100644
--- a/src/test/ui/traits/trait-item-privacy.stderr
+++ b/src/test/ui/traits/trait-item-privacy.stderr
@@ -112,23 +112,25 @@
 error[E0038]: the trait `assoc_const::C` cannot be made into an object
   --> $DIR/trait-item-privacy.rs:101:5
    |
-LL |         const A: u8 = 0;
-   |               - ...because it contains this associated `const`
-...
-LL |         const B: u8 = 0;
-   |               - ...because it contains this associated `const`
-...
-LL |     pub trait C: A + B {
-   |               - this trait cannot be made into an object...
-LL |         const C: u8 = 0;
-   |               - ...because it contains this associated `const`
-...
 LL |     C::A;
-   |     ^^^^ the trait `assoc_const::C` cannot be made into an object
+   |     ^^^^ `assoc_const::C` cannot be made into an object
    |
    = help: consider moving `C` to another trait
    = help: consider moving `B` to another trait
    = help: consider moving `A` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/trait-item-privacy.rs:25:15
+   |
+LL |         const A: u8 = 0;
+   |               ^ ...because it contains this associated `const`
+...
+LL |         const B: u8 = 0;
+   |               ^ ...because it contains this associated `const`
+...
+LL |     pub trait C: A + B {
+   |               - this trait cannot be made into an object...
+LL |         const C: u8 = 0;
+   |               ^ ...because it contains this associated `const`
 
 error[E0223]: ambiguous associated type
   --> $DIR/trait-item-privacy.rs:115:12
diff --git a/src/test/ui/traits/trait-object-bounds-cycle-1.rs b/src/test/ui/traits/trait-object-bounds-cycle-1.rs
new file mode 100644
index 0000000..3146764
--- /dev/null
+++ b/src/test/ui/traits/trait-object-bounds-cycle-1.rs
@@ -0,0 +1,24 @@
+// Check that we don't have a cycle when we try to normalize `Self::U` in the
+// bound below.
+
+// check-pass
+
+trait Is {
+    type T;
+}
+
+impl<U> Is for U {
+    type T = U;
+}
+
+trait Obj {
+    type U: Is<T = Self::U>;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32>) {
+    is_obj(x)
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-object-bounds-cycle-2.rs b/src/test/ui/traits/trait-object-bounds-cycle-2.rs
new file mode 100644
index 0000000..4c1df38
--- /dev/null
+++ b/src/test/ui/traits/trait-object-bounds-cycle-2.rs
@@ -0,0 +1,28 @@
+// Check that we don't have a cycle when we try to normalize `Self::V` in the
+// bound below.
+
+// check-pass
+
+trait Is {
+    type T;
+}
+
+impl<U> Is for U {
+    type T = U;
+}
+
+trait Super {
+    type V;
+}
+
+trait Obj: Super {
+    type U: Is<T = Self::V>;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32, V = i32>) {
+    is_obj(x)
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-object-bounds-cycle-3.rs b/src/test/ui/traits/trait-object-bounds-cycle-3.rs
new file mode 100644
index 0000000..55726a5
--- /dev/null
+++ b/src/test/ui/traits/trait-object-bounds-cycle-3.rs
@@ -0,0 +1,25 @@
+// Check that we don't have a cycle when we try to normalize `Self::V` in the
+// bound below.
+
+// check-pass
+
+trait Is {
+    type T;
+}
+
+impl<U> Is for U {
+    type T = U;
+}
+
+trait Obj {
+    type U: Is<T = Self::V>;
+    type V;
+}
+
+fn is_obj<T: ?Sized + Obj>(_: &T) {}
+
+fn f(x: &dyn Obj<U = i32, V = i32>) {
+    is_obj(x)
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-object-bounds-cycle-4.rs b/src/test/ui/traits/trait-object-bounds-cycle-4.rs
new file mode 100644
index 0000000..f83cb75
--- /dev/null
+++ b/src/test/ui/traits/trait-object-bounds-cycle-4.rs
@@ -0,0 +1,25 @@
+// Check that we don't have a cycle when we try to normalize `Self::U` in the
+// bound below. Make sure that having a lifetime on the trait object doesn't break things
+
+// check-pass
+
+trait Is {
+    type T;
+}
+
+impl<U> Is for U {
+    type T = U;
+}
+
+trait Obj<'a> {
+    type U: Is<T = Self::V>;
+    type V;
+}
+
+fn is_obj<'a, T: ?Sized + Obj<'a>>(_: &T) {}
+
+fn f<'a>(x: &dyn Obj<'a, U = i32, V = i32>) {
+    is_obj(x)
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-object-macro-matcher.stderr b/src/test/ui/traits/trait-object-macro-matcher.stderr
index bc56736..335eeb8 100644
--- a/src/test/ui/traits/trait-object-macro-matcher.stderr
+++ b/src/test/ui/traits/trait-object-macro-matcher.stderr
@@ -8,9 +8,10 @@
   --> $DIR/trait-object-macro-matcher.rs:8:8
    |
 LL |     m!(dyn Copy + Send + 'static);
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` cannot be made into an object
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object
    |
    = note: the trait cannot be made into an object because it requires `Self: Sized`
+   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr
index 3fa7c0c..16f6096 100644
--- a/src/test/ui/traits/trait-object-safety.stderr
+++ b/src/test/ui/traits/trait-object-safety.stderr
@@ -1,17 +1,23 @@
 error[E0038]: the trait `Tr` cannot be made into an object
   --> $DIR/trait-object-safety.rs:15:22
    |
+LL |     let _: &dyn Tr = &St;
+   |                      ^^^ `Tr` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/trait-object-safety.rs:4:8
+   |
 LL | trait Tr {
    |       -- this trait cannot be made into an object...
 LL |     fn foo();
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL |     let _: &dyn Tr = &St;
-   |                      ^^^ the trait `Tr` cannot be made into an object
-   |
+   |        ^^^ ...because associated function `foo` has no `self` parameter
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Tr>` for `&St`
    = note: required by cast to type `&dyn Tr`
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+help: consider turning `foo` into a method by giving it a `&self` argument
+   |
+LL |     fn foo(&self);
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() where Self: Sized;
    |              ^^^^^^^^^^^^^^^^^
@@ -19,15 +25,21 @@
 error[E0038]: the trait `Tr` cannot be made into an object
   --> $DIR/trait-object-safety.rs:15:12
    |
+LL |     let _: &dyn Tr = &St;
+   |            ^^^^^^^ `Tr` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/trait-object-safety.rs:4:8
+   |
 LL | trait Tr {
    |       -- this trait cannot be made into an object...
 LL |     fn foo();
-   |        --- ...because associated function `foo` has no `self` parameter
-...
-LL |     let _: &dyn Tr = &St;
-   |            ^^^^^^^ the trait `Tr` cannot be made into an object
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+help: consider turning `foo` into a method by giving it a `&self` argument
    |
-help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+LL |     fn foo(&self);
+   |            ^^^^^
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
    |
 LL |     fn foo() where Self: Sized;
    |              ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/traits/trait-object-supertrait-lifetime-bound.rs b/src/test/ui/traits/trait-object-supertrait-lifetime-bound.rs
new file mode 100644
index 0000000..9d83472
--- /dev/null
+++ b/src/test/ui/traits/trait-object-supertrait-lifetime-bound.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+use std::any::Any;
+
+trait A<T>: Any {
+    fn m(&self) {}
+}
+
+impl<S, T: 'static> A<S> for T {}
+
+fn call_obj<'a>() {
+    let obj: &dyn A<&'a ()> = &();
+    obj.m();
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.rs b/src/test/ui/traits/trait-resolution-in-overloaded-op.rs
index 2867769..a9bacc3 100644
--- a/src/test/ui/traits/trait-resolution-in-overloaded-op.rs
+++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.rs
@@ -5,7 +5,7 @@
 }
 
 fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 {
-    a * b //~ ERROR cannot multiply `f64` to `&T`
+    a * b //~ ERROR cannot multiply `&T` by `f64`
 }
 
 fn main() {}
diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
index 507d53d..ada76cd 100644
--- a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
+++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
@@ -1,4 +1,4 @@
-error[E0369]: cannot multiply `f64` to `&T`
+error[E0369]: cannot multiply `&T` by `f64`
   --> $DIR/trait-resolution-in-overloaded-op.rs:8:7
    |
 LL |     a * b
diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr
index 0a62f1a..a06f6a4 100644
--- a/src/test/ui/traits/trait-test-2.stderr
+++ b/src/test/ui/traits/trait-test-2.stderr
@@ -13,32 +13,36 @@
 error[E0038]: the trait `bar` cannot be made into an object
   --> $DIR/trait-test-2.rs:11:16
    |
-LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
-   |       ---                    ----     ---- ...because method `blah` has generic type parameters
-   |       |                      |
-   |       |                      ...because method `dup` references the `Self` type in its return type
-   |       this trait cannot be made into an object...
-...
 LL |     (box 10 as Box<dyn bar>).dup();
-   |                ^^^^^^^^^^^^ the trait `bar` cannot be made into an object
+   |                ^^^^^^^^^^^^ `bar` cannot be made into an object
    |
    = help: consider moving `dup` to another trait
    = help: consider moving `blah` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/trait-test-2.rs:4:30
+   |
+LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
+   |       ---                    ^^^^     ^^^^ ...because method `blah` has generic type parameters
+   |       |                      |
+   |       |                      ...because method `dup` references the `Self` type in its return type
+   |       this trait cannot be made into an object...
 
 error[E0038]: the trait `bar` cannot be made into an object
   --> $DIR/trait-test-2.rs:11:6
    |
-LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
-   |       ---                    ----     ---- ...because method `blah` has generic type parameters
-   |       |                      |
-   |       |                      ...because method `dup` references the `Self` type in its return type
-   |       this trait cannot be made into an object...
-...
 LL |     (box 10 as Box<dyn bar>).dup();
-   |      ^^^^^^ the trait `bar` cannot be made into an object
+   |      ^^^^^^ `bar` cannot be made into an object
    |
    = help: consider moving `dup` to another trait
    = help: consider moving `blah` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/trait-test-2.rs:4:30
+   |
+LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
+   |       ---                    ^^^^     ^^^^ ...because method `blah` has generic type parameters
+   |       |                      |
+   |       |                      ...because method `dup` references the `Self` type in its return type
+   |       this trait cannot be made into an object...
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
    = note: required by cast to type `Box<dyn bar>`
 
diff --git a/src/test/ui/traits/traits-inductive-overflow-two-traits.rs b/src/test/ui/traits/traits-inductive-overflow-two-traits.rs
index 63dd141..463b55d 100644
--- a/src/test/ui/traits/traits-inductive-overflow-two-traits.rs
+++ b/src/test/ui/traits/traits-inductive-overflow-two-traits.rs
@@ -9,6 +9,7 @@
 }
 impl<T: Magic> Magic for T {
     type X = Self;
+    //~^ ERROR E0277
 }
 
 fn check<T: Trait>() {}
diff --git a/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr b/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr
index f66cfce..996544ae 100644
--- a/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr
+++ b/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr
@@ -1,5 +1,19 @@
+error[E0277]: `T` cannot be shared between threads safely
+  --> $DIR/traits-inductive-overflow-two-traits.rs:11:5
+   |
+LL |     type X: Trait;
+   |             ----- required by this bound in `Magic::X`
+...
+LL |     type X = Self;
+   |     ^^^^^^^^^^^^^^ `T` cannot be shared between threads safely
+   |
+help: consider further restricting this bound
+   |
+LL | impl<T: Magic + Sync> Magic for T {
+   |               ^^^^^^
+
 error[E0275]: overflow evaluating the requirement `*mut (): Magic`
-  --> $DIR/traits-inductive-overflow-two-traits.rs:19:5
+  --> $DIR/traits-inductive-overflow-two-traits.rs:20:5
    |
 LL | fn wizard<T: Magic>() { check::<<T as Magic>::X>(); }
    |              ----- required by this bound in `wizard`
@@ -7,6 +21,7 @@
 LL |     wizard::<*mut ()>();
    |     ^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0275`.
+Some errors have detailed explanations: E0275, E0277.
+For more information about an error, try `rustc --explain E0275`.
diff --git a/src/test/ui/transmute-specialization.stderr b/src/test/ui/transmute-specialization.stderr
index 0231505..a0ea724 100644
--- a/src/test/ui/transmute-specialization.stderr
+++ b/src/test/ui/transmute-specialization.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/transmute/main.rs b/src/test/ui/transmute/main.rs
index ea233a4..cb46fc5 100644
--- a/src/test/ui/transmute/main.rs
+++ b/src/test/ui/transmute/main.rs
@@ -1,9 +1,6 @@
 // normalize-stderr-32bit: "`&str` \(64 bits\)" -> "`&str` ($$STR bits)"
 // normalize-stderr-64bit: "`&str` \(128 bits\)" -> "`&str` ($$STR bits)"
 
-
-
-#![feature(untagged_unions)]
 use std::mem::transmute;
 
 pub trait TypeConstructor<'a> {
diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr
index 4e78131..f485620 100644
--- a/src/test/ui/transmute/main.stderr
+++ b/src/test/ui/transmute/main.stderr
@@ -1,5 +1,5 @@
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/main.rs:16:5
+  --> $DIR/main.rs:13:5
    |
 LL |     transmute(x)
    |     ^^^^^^^^^
@@ -7,7 +7,7 @@
    = note: `<C as TypeConstructor>::T` does not have a fixed size
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/main.rs:20:17
+  --> $DIR/main.rs:17:17
    |
 LL |     let x: u8 = transmute(10u16);
    |                 ^^^^^^^^^
@@ -16,7 +16,7 @@
    = note: target type: `u8` (8 bits)
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/main.rs:24:17
+  --> $DIR/main.rs:21:17
    |
 LL |     let x: u8 = transmute("test");
    |                 ^^^^^^^^^
@@ -25,7 +25,7 @@
    = note: target type: `u8` (8 bits)
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/main.rs:29:18
+  --> $DIR/main.rs:26:18
    |
 LL |     let x: Foo = transmute(10);
    |                  ^^^^^^^^^
diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
index 08c7951..edb48b6 100644
--- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
+++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr
@@ -7,7 +7,7 @@
 LL |     B::get_x()
    |     ^^^^^^^^^^ expected `u8`, found `i32`
    |
-help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit
    |
 LL |     B::get_x().try_into().unwrap()
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/try-block/try-block-bad-lifetime.rs b/src/test/ui/try-block/try-block-bad-lifetime.rs
index 6063e2e..d9524e9 100644
--- a/src/test/ui/try-block/try-block-bad-lifetime.rs
+++ b/src/test/ui/try-block/try-block-bad-lifetime.rs
@@ -2,7 +2,7 @@
 
 #![feature(try_blocks)]
 
-#![inline(never)]
+#[inline(never)]
 fn do_something_with<T>(_x: T) {}
 
 // This test checks that borrows made and returned inside try blocks are properly constrained
diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs
index c338294..496ba14 100644
--- a/src/test/ui/try-block/try-block-bad-type.rs
+++ b/src/test/ui/try-block/try-block-bad-type.rs
@@ -14,7 +14,9 @@
 
     let res: Result<i32, i32> = try { }; //~ ERROR type mismatch
 
-    let res: () = try { }; //~ the trait bound `(): Try` is not satisfied
+    let res: () = try { };
+    //~^ ERROR the trait bound `(): Try` is not satisfied
+    //~| ERROR the trait bound `(): Try` is not satisfied
 
     let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied
 }
diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr
index 03d5d36..cadf3a8 100644
--- a/src/test/ui/try-block/try-block-bad-type.stderr
+++ b/src/test/ui/try-block/try-block-bad-type.stderr
@@ -26,22 +26,28 @@
    |                                       ^ expected `i32`, found `()`
 
 error[E0277]: the trait bound `(): Try` is not satisfied
-  --> $DIR/try-block-bad-type.rs:17:23
+  --> $DIR/try-block-bad-type.rs:17:25
    |
 LL |     let res: () = try { };
-   |                       ^^^ the trait `Try` is not implemented for `()`
+   |                         ^ the trait `Try` is not implemented for `()`
    |
    = note: required by `from_ok`
 
+error[E0277]: the trait bound `(): Try` is not satisfied
+  --> $DIR/try-block-bad-type.rs:17:25
+   |
+LL |     let res: () = try { };
+   |                         ^ the trait `Try` is not implemented for `()`
+
 error[E0277]: the trait bound `i32: Try` is not satisfied
-  --> $DIR/try-block-bad-type.rs:19:24
+  --> $DIR/try-block-bad-type.rs:21:26
    |
 LL |     let res: i32 = try { 5 };
-   |                        ^^^^^ the trait `Try` is not implemented for `i32`
+   |                          ^ the trait `Try` is not implemented for `i32`
    |
    = note: required by `from_ok`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0271, E0277.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr
index bc0f5bb..75a4e8d 100644
--- a/src/test/ui/try-block/try-block-in-while.stderr
+++ b/src/test/ui/try-block/try-block-in-while.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `bool: Try` is not satisfied
-  --> $DIR/try-block-in-while.rs:6:15
+  --> $DIR/try-block-in-while.rs:6:17
    |
 LL |     while try { false } {}
-   |               ^^^^^^^^^ the trait `Try` is not implemented for `bool`
+   |                 ^^^^^ the trait `Try` is not implemented for `bool`
    |
    = note: required by `from_ok`
 
diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs b/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs
index 1d1c3d9..cd2ddf6 100644
--- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs
+++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.rs
@@ -2,7 +2,7 @@
 
 #![feature(try_blocks)]
 
-#![inline(never)]
+#[inline(never)]
 fn do_something_with<T>(_x: T) {}
 
 // This test checks that borrows made and returned inside try blocks are properly constrained
diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr
index 800b5a3..8d22f45 100644
--- a/src/test/ui/tuple/index-invalid.stderr
+++ b/src/test/ui/tuple/index-invalid.stderr
@@ -2,19 +2,19 @@
   --> $DIR/index-invalid.rs:2:22
    |
 LL |     let _ = (((),),).1.0;
-   |                      ^^^
+   |                      ^
 
 error[E0609]: no field `1` on type `((),)`
-  --> $DIR/index-invalid.rs:4:22
+  --> $DIR/index-invalid.rs:4:24
    |
 LL |     let _ = (((),),).0.1;
-   |                      ^^^
+   |                        ^
 
 error[E0609]: no field `000` on type `(((),),)`
   --> $DIR/index-invalid.rs:6:22
    |
 LL |     let _ = (((),),).000.000;
-   |                      ^^^^^^^
+   |                      ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr
index c6c7ba2..f9974ac 100644
--- a/src/test/ui/tutorial-suffix-inference-test.stderr
+++ b/src/test/ui/tutorial-suffix-inference-test.stderr
@@ -5,7 +5,7 @@
    |                  ^
    |                  |
    |                  expected `u16`, found `u8`
-   |                  help: you can convert an `u8` to `u16`: `x.into()`
+   |                  help: you can convert a `u8` to a `u16`: `x.into()`
 
 error[E0308]: mismatched types
   --> $DIR/tutorial-suffix-inference-test.rs:12:18
@@ -13,7 +13,7 @@
 LL |     identity_u16(y);
    |                  ^ expected `u16`, found `i32`
    |
-help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     identity_u16(y.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@
 LL |     identity_u16(a);
    |                  ^ expected `u16`, found `isize`
    |
-help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit
    |
 LL |     identity_u16(a.try_into().unwrap());
    |                  ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr
index 46e7dd0..20e2605 100644
--- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr
+++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5
    |
-LL |     V(u8)
-   |     ----- defined here
-...
 LL |     <E>::V();
    |     ^^^^^^-- supplied 0 arguments
    |     |
    |     expected 1 argument
+   |
+note: tuple variant defined here
+  --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:5:5
+   |
+LL |     V(u8)
+   |     ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17
diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr
index e0c1b02..c5b22f0 100644
--- a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr
+++ b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr
@@ -6,6 +6,7 @@
    |
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+   = help: consider using `min_const_generics` instead, which is more stable and complete
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
index 0a4cc9b..a15074c 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
@@ -1,19 +1,18 @@
 #![feature(type_alias_impl_trait)]
 
-fn main() {
-}
+fn main() {}
 
 trait TraitWithAssoc {
     type Assoc;
 }
 
 type Foo<V> = impl Trait<V>;
-//~^ ERROR the trait bound `T: TraitWithAssoc` is not satisfied
 
 trait Trait<U> {}
 
 impl<W> Trait<W> for () {}
 
 fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
+    //~^ ERROR non-defining opaque type use in defining scope
     ()
 }
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
index 9ebf6346..c9d6a43 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
@@ -1,14 +1,14 @@
-error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied
-  --> $DIR/bound_reduction2.rs:10:15
+error: non-defining opaque type use in defining scope
+  --> $DIR/bound_reduction2.rs:15:46
+   |
+LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
+   |                                              ^^^^^^^^^^^^^
+   |
+note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
+  --> $DIR/bound_reduction2.rs:9:10
    |
 LL | type Foo<V> = impl Trait<V>;
-   |               ^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T`
-   |
-help: consider further restricting this bound
-   |
-LL | fn foo_desugared<T: TraitWithAssoc + TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-   |                                    ^^^^^^^^^^^^^^^^
+   |          ^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs
new file mode 100644
index 0000000..c035915
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.rs
@@ -0,0 +1,19 @@
+// Make sure that we check that impl trait types implement the traits that they
+// claim to.
+
+#![feature(type_alias_impl_trait)]
+
+type X<T> = impl Clone;
+//~^ ERROR the trait bound `T: Clone` is not satisfied
+
+fn f<T: Clone>(t: T) -> X<T> {
+    t
+}
+
+fn g<T>(o: Option<X<T>>) -> Option<X<T>> {
+    o.clone()
+}
+
+fn main() {
+    g(None::<X<&mut ()>>);
+}
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
new file mode 100644
index 0000000..26a2f41
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `T: Clone` is not satisfied
+  --> $DIR/bounds-are-checked-2.rs:6:13
+   |
+LL | type X<T> = impl Clone;
+   |             ^^^^^^^^^^ the trait `Clone` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | type X<T: Clone> = impl Clone;
+   |         ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs b/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
new file mode 100644
index 0000000..759bf4f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.rs
@@ -0,0 +1,25 @@
+// Make sure that we check that impl trait types implement the traits that they
+// claim to.
+
+#![feature(type_alias_impl_trait)]
+
+type X<'a> = impl Into<&'static str> + From<&'a str>;
+//~^ ERROR mismatched types
+
+fn f<'a: 'static>(t: &'a str) -> X<'a> {
+    //~^ WARNING unnecessary lifetime parameter
+    t
+}
+
+fn extend_lt<'a>(o: &'a str) -> &'static str {
+    X::<'_>::from(o).into()
+}
+
+fn main() {
+    let r =
+    {
+        let s = "abcdef".to_string();
+        extend_lt(&s)
+    };
+    println!("{}", r);
+}
diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
new file mode 100644
index 0000000..d5fafe0
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr
@@ -0,0 +1,26 @@
+warning: unnecessary lifetime parameter `'a`
+  --> $DIR/bounds-are-checked.rs:9:6
+   |
+LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
+   |      ^^^^^^^^^^^
+   |
+   = help: you can use the `'static` lifetime directly, in place of `'a`
+
+error[E0308]: mismatched types
+  --> $DIR/bounds-are-checked.rs:6:14
+   |
+LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected trait `From<&'a str>`
+              found trait `From<&'static str>`
+note: the lifetime `'a` as defined on the item at 6:8...
+  --> $DIR/bounds-are-checked.rs:6:8
+   |
+LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
+   |        ^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs
index 09873a8..7ea517e 100644
--- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs
+++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs
@@ -9,4 +9,5 @@
 
 fn bomp() -> boo::Boo {
     ""
+    //~^ mismatched types
 }
diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr
index c0cb94b..0b4c262 100644
--- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr
+++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr
@@ -4,5 +4,20 @@
 LL |     pub type Boo = impl ::std::fmt::Debug;
    |                    ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/declared_but_not_defined_in_scope.rs:11:5
+   |
+LL |     pub type Boo = impl ::std::fmt::Debug;
+   |                    ---------------------- the expected opaque type
+...
+LL | fn bomp() -> boo::Boo {
+   |              -------- expected `impl Debug` because of return type
+LL |     ""
+   |     ^^ expected opaque type, found `&str`
+   |
+   = note: expected opaque type `impl Debug`
+                found reference `&'static str`
 
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs
index 898dab1..c17d595 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use10.rs
@@ -1,11 +1,11 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![feature(type_alias_impl_trait)]
 
 use std::fmt::Debug;
 
 fn main() {}
 
-type Two<T, U> = impl Debug;
+type Two<T: Debug, U> = impl Debug;
 
 fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
     (t, 4u32)
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs
index 2b98d8f..a74731d 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs
@@ -8,10 +8,10 @@
 type Two<T, U> = impl Debug;
 
 fn one<T: Debug>(t: T) -> Two<T, T> {
+    //~^ ERROR non-defining opaque type use in defining scope
     t
 }
 
 fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
-//~^ ERROR concrete type differs from previous defining opaque type use
     t
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
index 7900da4..d87e8c5 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
@@ -1,14 +1,14 @@
-error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use2.rs:14:1
-   |
-LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T`
-   |
-note: previous use here
-  --> $DIR/generic_duplicate_param_use2.rs:10:1
+error: non-defining opaque type use in defining scope
+  --> $DIR/generic_duplicate_param_use2.rs:10:27
    |
 LL | fn one<T: Debug>(t: T) -> Two<T, T> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                           ^^^^^^^^^
+   |
+note: type used multiple times
+  --> $DIR/generic_duplicate_param_use2.rs:8:10
+   |
+LL | type Two<T, U> = impl Debug;
+   |          ^  ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
index d9133fd..0597b83 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
@@ -8,11 +8,11 @@
 type Two<T, U> = impl Debug;
 
 fn one<T: Debug>(t: T) -> Two<T, T> {
+    //~^ ERROR non-defining opaque type use in defining scope
     t
 }
 
 fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
-//~^ ERROR concrete type differs from previous defining opaque type use
     t
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
index ac5f794..711de85 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
@@ -1,14 +1,14 @@
-error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use3.rs:14:1
-   |
-LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T`
-   |
-note: previous use here
-  --> $DIR/generic_duplicate_param_use3.rs:10:1
+error: non-defining opaque type use in defining scope
+  --> $DIR/generic_duplicate_param_use3.rs:10:27
    |
 LL | fn one<T: Debug>(t: T) -> Two<T, T> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                           ^^^^^^^^^
+   |
+note: type used multiple times
+  --> $DIR/generic_duplicate_param_use3.rs:8:10
+   |
+LL | type Two<T, U> = impl Debug;
+   |          ^  ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
index ac87731..dd2f202 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
@@ -6,12 +6,14 @@
 
 // test that unused generic parameters are ok
 type Two<T, U> = impl Debug;
+//~^ ERROR `T` doesn't implement `Debug`
+//~| ERROR `U` doesn't implement `Debug`
 
 fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
     (t, u)
 }
 
 fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-//~^ concrete type differs from previous
+    //~^ concrete type differs from previous
     (u, t)
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
index 1ddbc0c..b4aed4a 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
@@ -1,14 +1,39 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use5.rs:14:1
+  --> $DIR/generic_duplicate_param_use5.rs:16:1
    |
 LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, U)`, got `(U, T)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use5.rs:10:1
+  --> $DIR/generic_duplicate_param_use5.rs:12:1
    |
 LL | fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0277]: `T` doesn't implement `Debug`
+  --> $DIR/generic_duplicate_param_use5.rs:8:18
+   |
+LL | type Two<T, U> = impl Debug;
+   |                  ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+   = note: required because of the requirements on the impl of `Debug` for `(T, U)`
+help: consider restricting type parameter `T`
+   |
+LL | type Two<T: Debug, U> = impl Debug;
+   |           ^^^^^^^
 
+error[E0277]: `U` doesn't implement `Debug`
+  --> $DIR/generic_duplicate_param_use5.rs:8:18
+   |
+LL | type Two<T, U> = impl Debug;
+   |                  ^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+   = note: required because of the requirements on the impl of `Debug` for `(T, U)`
+help: consider restricting type parameter `U`
+   |
+LL | type Two<T, U: Debug> = impl Debug;
+   |              ^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
index 6cbb306..d54d3cd 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
@@ -6,12 +6,13 @@
 
 // test that unused generic parameters are ok
 type Two<T, U> = impl Debug;
+//~^ ERROR `T` doesn't implement `Debug`
 
 fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
     (t, t)
 }
 
 fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
-    //~^ concrete type differs from previous
+    //~^ ERROR concrete type differs from previous
     (u, t)
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
index ebd07b7..22e4d00 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
@@ -1,14 +1,27 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use6.rs:14:1
+  --> $DIR/generic_duplicate_param_use6.rs:15:1
    |
 LL | fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, T)`, got `(U, T)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use6.rs:10:1
+  --> $DIR/generic_duplicate_param_use6.rs:11:1
    |
 LL | fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0277]: `T` doesn't implement `Debug`
+  --> $DIR/generic_duplicate_param_use6.rs:8:18
+   |
+LL | type Two<T, U> = impl Debug;
+   |                  ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+   = note: required because of the requirements on the impl of `Debug` for `(T, T)`
+help: consider restricting type parameter `T`
+   |
+LL | type Two<T: Debug, U> = impl Debug;
+   |           ^^^^^^^
 
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs
index 712a653..feebf81 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use7.rs
@@ -1,11 +1,11 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![feature(type_alias_impl_trait)]
 
 use std::fmt::Debug;
 
 fn main() {}
 
-type Two<A, B> = impl Debug;
+type Two<A: Debug, B> = impl Debug;
 
 fn two<T: Debug + Copy, U>(t: T, u: U) -> Two<T, U> {
     (t, t)
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
index 777ded5..4a723b6 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
@@ -5,12 +5,13 @@
 fn main() {}
 
 type Two<T, U> = impl Debug;
+//~^ ERROR `T` doesn't implement `Debug`
 
 fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
     (t, 4u32)
 }
 
 fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
-//~^ concrete type differs from previous
+    //~^ concrete type differs from previous
     (u, 4u32)
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
index 4778ee5..82da704 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
@@ -1,14 +1,27 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use8.rs:13:1
+  --> $DIR/generic_duplicate_param_use8.rs:14:1
    |
 LL | fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use8.rs:9:1
+  --> $DIR/generic_duplicate_param_use8.rs:10:1
    |
 LL | fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0277]: `T` doesn't implement `Debug`
+  --> $DIR/generic_duplicate_param_use8.rs:7:18
+   |
+LL | type Two<T, U> = impl Debug;
+   |                  ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+   = note: required because of the requirements on the impl of `Debug` for `(T, u32)`
+help: consider restricting type parameter `T`
+   |
+LL | type Two<T: Debug, U> = impl Debug;
+   |           ^^^^^^^
 
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
index 491e664..7470819 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
@@ -5,6 +5,9 @@
 fn main() {}
 
 type Two<A, B> = impl Debug;
+//~^ ERROR the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+//~| ERROR `A` doesn't implement `Debug`
+//~| ERROR `B` doesn't implement `Debug`
 
 trait Foo {
     type Bar: Debug;
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
index 247b042..63aa0f8 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
@@ -1,14 +1,51 @@
 error: concrete type differs from previous defining opaque type use
-  --> $DIR/generic_duplicate_param_use9.rs:18:1
+  --> $DIR/generic_duplicate_param_use9.rs:21:1
    |
 LL | fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
    |
 note: previous use here
-  --> $DIR/generic_duplicate_param_use9.rs:14:1
+  --> $DIR/generic_duplicate_param_use9.rs:17:1
    |
 LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+  --> $DIR/generic_duplicate_param_use9.rs:7:18
+   |
+LL | type Two<A, B> = impl Debug;
+   |                  ^^^^^^^^^^ within `(A, B, <A as Foo>::Bar)`, the trait `Foo` is not implemented for `A`
+   |
+   = note: required because it appears within the type `(A, B, <A as Foo>::Bar)`
+help: consider restricting type parameter `A`
+   |
+LL | type Two<A: Foo, B> = impl Debug;
+   |           ^^^^^
 
+error[E0277]: `A` doesn't implement `Debug`
+  --> $DIR/generic_duplicate_param_use9.rs:7:18
+   |
+LL | type Two<A, B> = impl Debug;
+   |                  ^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+   = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+help: consider restricting type parameter `A`
+   |
+LL | type Two<A: Debug, B> = impl Debug;
+   |           ^^^^^^^
+
+error[E0277]: `B` doesn't implement `Debug`
+  --> $DIR/generic_duplicate_param_use9.rs:7:18
+   |
+LL | type Two<A, B> = impl Debug;
+   |                  ^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+   = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+help: consider restricting type parameter `B`
+   |
+LL | type Two<A, B: Debug> = impl Debug;
+   |              ^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
index 76654d7..ffd6f34 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr
@@ -18,6 +18,24 @@
    = note:     expected type `i32`
            found opaque type `impl Sized`
 
-error: aborting due to 2 previous errors
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/generic_type_does_not_live_long_enough.rs:14:30
+   |
+LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
+   |                              ^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
 
-For more information about this error, try `rustc --explain E0308`.
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+   |
+LL | type WrongGeneric<T> = impl 'static;
+   |                        ^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+   = note: ...so that the type `T` will meet its required lifetime bounds
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0310.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
index c0f939a..f6d4909 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
@@ -8,7 +8,8 @@
 
 type WrongGeneric<T> = impl 'static;
 //~^ ERROR the parameter type `T` may not live long enough
-//~^^ ERROR: at least one trait must be specified
+//~| ERROR the parameter type `T` may not live long enough
+//~| ERROR: at least one trait must be specified
 
 fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
     t
diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
index 18d8daa..4924c44 100644
--- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
@@ -27,7 +27,16 @@
 LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
    |                  - help: consider adding an explicit lifetime bound...: `T: 'static`
 
-error: aborting due to 3 previous errors
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/generic_type_does_not_live_long_enough.rs:9:24
+   |
+LL | type WrongGeneric<T> = impl 'static;
+   |                        ^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+   = note: ...so that the type `T` will meet its required lifetime bounds
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0308, E0310.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs
index 589612d..766ee36 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs
@@ -3,10 +3,11 @@
 fn main() {}
 
 trait Trait {}
-type Underconstrained<T: Trait> = impl 'static; //~ ERROR the trait bound `T: Trait`
+type Underconstrained<T: Trait> = impl 'static;
 //~^ ERROR: at least one trait must be specified
 
 // no `Trait` bound
 fn underconstrain<T>(_: T) -> Underconstrained<T> {
+    //~^ ERROR the trait bound `T: Trait`
     unimplemented!()
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
index 911f592..cefc5d9 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
@@ -5,12 +5,14 @@
    |                                   ^^^^^^^^^^^^
 
 error[E0277]: the trait bound `T: Trait` is not satisfied
-  --> $DIR/generic_underconstrained.rs:6:35
+  --> $DIR/generic_underconstrained.rs:10:31
    |
 LL | type Underconstrained<T: Trait> = impl 'static;
-   |                                   ^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
+   |                          ----- required by this bound in `Underconstrained`
+...
+LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
+   |                               ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
    |
-   = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `T`
    |
 LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> {
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs
index 4ac32e8..cd7c962 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs
@@ -3,19 +3,19 @@
 fn main() {}
 
 type Underconstrained<T: std::fmt::Debug> = impl 'static;
-//~^ ERROR `U` doesn't implement `Debug`
-//~^^ ERROR: at least one trait must be specified
+//~^ ERROR: at least one trait must be specified
 
 // not a defining use, because it doesn't define *all* possible generics
 fn underconstrained<U>(_: U) -> Underconstrained<U> {
+    //~^ ERROR `U` doesn't implement `Debug`
     5u32
 }
 
 type Underconstrained2<T: std::fmt::Debug> = impl 'static;
-//~^ ERROR `V` doesn't implement `Debug`
-//~^^ ERROR: at least one trait must be specified
+//~^ ERROR: at least one trait must be specified
 
 // not a defining use, because it doesn't define *all* possible generics
 fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
+    //~^ ERROR `V` doesn't implement `Debug`
     5u32
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index 5ff82d4..669546a 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -11,30 +11,28 @@
    |                                              ^^^^^^^^^^^^
 
 error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:5:45
+  --> $DIR/generic_underconstrained2.rs:9:33
    |
 LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
-   |                                             ^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |                          --------------- required by this bound in `Underconstrained`
 ...
-LL |     5u32
-   |     ---- this returned value is of type `u32`
+LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
+   |                                 ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
-   = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `U`
    |
 LL | fn underconstrained<U: Debug>(_: U) -> Underconstrained<U> {
    |                      ^^^^^^^
 
 error[E0277]: `V` doesn't implement `Debug`
-  --> $DIR/generic_underconstrained2.rs:14:46
+  --> $DIR/generic_underconstrained2.rs:18:43
    |
 LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
-   |                                              ^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |                           --------------- required by this bound in `Underconstrained2`
 ...
-LL |     5u32
-   |     ---- this returned value is of type `u32`
+LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
+   |                                           ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
-   = note: the return type of a function must have a statically known size
 help: consider restricting type parameter `V`
    |
 LL | fn underconstrained2<U, V: Debug>(_: U, _: V) -> Underconstrained2<V> {
diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs
index bc6543a..851c2f6 100644
--- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs
+++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs
@@ -9,10 +9,9 @@
 }
 
 impl<T> X for () {
+    //~^ ERROR the type parameter `T` is not constrained
     type I = impl Sized;
-    //~^ ERROR could not find defining uses
     fn f() -> Self::I {}
-    //~^ ERROR type annotations needed
 }
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr
index e8b6771..8cf8fb1 100644
--- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr
+++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr
@@ -1,15 +1,9 @@
-error[E0282]: type annotations needed
-  --> $DIR/impl-with-unconstrained-param.rs:14:23
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/impl-with-unconstrained-param.rs:11:6
    |
-LL |     fn f() -> Self::I {}
-   |                       ^^ cannot infer type for type parameter `T`
+LL | impl<T> X for () {
+   |      ^ unconstrained type parameter
 
-error: could not find defining uses
-  --> $DIR/impl-with-unconstrained-param.rs:12:14
-   |
-LL |     type I = impl Sized;
-   |              ^^^^^^^^^^
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr
index cb893c4..eafbd2a 100644
--- a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr
+++ b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr
@@ -14,7 +14,7 @@
 LL | impl<F> FnOnce<()> for &F {
    |      ^ type parameter `F` must be used as the type parameter for some local type
    |
-   = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.rs b/src/test/ui/type-alias-impl-trait/issue-52843.rs
new file mode 100644
index 0000000..b24959d
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-52843.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl Default;
+//~^ ERROR: the trait bound `T: Default` is not satisfied
+
+#[allow(unused)]
+fn foo<T: Default>(t: T) -> Foo<T> {
+    t
+}
+
+struct NotDefault;
+
+fn main() {
+    let _ = Foo::<NotDefault>::default();
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.stderr b/src/test/ui/type-alias-impl-trait/issue-52843.stderr
new file mode 100644
index 0000000..25db8df
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-52843.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `T: Default` is not satisfied
+  --> $DIR/issue-52843.rs:3:15
+   |
+LL | type Foo<T> = impl Default;
+   |               ^^^^^^^^^^^^ the trait `Default` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | type Foo<T: Default> = impl Default;
+   |           ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-53096.rs b/src/test/ui/type-alias-impl-trait/issue-53096.rs
index 564c5c3..6e1973b 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53096.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53096.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(const_fn)]
+#![feature(const_impl_trait, const_fn_fn_ptr_basics)]
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Fn() -> usize;
diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.rs b/src/test/ui/type-alias-impl-trait/issue-53598.rs
index 61dff79..add9662 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53598.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53598.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-linelength
+// ignore-compare-mode-chalk
 #![feature(type_alias_impl_trait)]
 
 use std::fmt::Debug;
diff --git a/src/test/ui/type-alias-impl-trait/issue-53598.stderr b/src/test/ui/type-alias-impl-trait/issue-53598.stderr
index 4c8144a..79e2682 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53598.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-53598.stderr
@@ -1,5 +1,5 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-53598.rs:20:42
+  --> $DIR/issue-53598.rs:21:42
    |
 LL |       fn foo<T: Debug>(_: T) -> Self::Item {
    |  __________________________________________^
diff --git a/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs b/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
index e7f9373..4582d53 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_fn, generators, generator_trait, type_alias_impl_trait)]
+#![feature(const_impl_trait, generators, generator_trait, type_alias_impl_trait)]
 
 use std::ops::Generator;
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
index 8c9cb74..790aea8 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
@@ -1,14 +1,33 @@
 error: higher-ranked subtype error
-  --> $DIR/issue-57611-trait-alias.rs:21:9
+  --> $DIR/issue-57611-trait-alias.rs:25:9
    |
 LL |         |x| x
    |         ^^^^^
 
 error: higher-ranked subtype error
-  --> $DIR/issue-57611-trait-alias.rs:21:9
+  --> $DIR/issue-57611-trait-alias.rs:25:9
    |
 LL |         |x| x
    |         ^^^^^
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> Fn<(&'r X,)>`
+              found type `Fn<(&'static X,)>`
 
+error[E0308]: mismatched types
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `FnOnce<(&X,)>`
+              found type `FnOnce<(&'static X,)>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
index 41e0192..3372b81 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
@@ -16,12 +16,16 @@
 impl Foo for X {
     type Bar = impl Baz<Self, Self>;
     //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
 
     fn bar(&self) -> Self::Bar {
         |x| x
     }
 }
 
-trait Baz<A, B> = Fn(&A) -> &B;
+trait Baz<A: ?Sized, B: ?Sized> = Fn(&A) -> &B;
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
index a8706aa..5e2a8db 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
@@ -7,6 +7,42 @@
    = note: expected type `FnOnce<(&X,)>`
               found type `FnOnce<(&X,)>`
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> Fn<(&'r X,)>`
+              found type `Fn<(&'<empty> X,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `FnOnce<(&X,)>`
+              found type `FnOnce<(&'<empty> X,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> Fn<(&'r X,)>`
+              found type `Fn<(&'<empty> X,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `FnOnce<(&X,)>`
+              found type `FnOnce<(&'<empty> X,)>`
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.rs b/src/test/ui/type-alias-impl-trait/issue-57700.rs
index bfabef5..c785ea2 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57700.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57700.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-linelength
+// ignore-compare-mode-chalk
 #![feature(arbitrary_self_types)]
 #![feature(type_alias_impl_trait)]
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-57700.stderr b/src/test/ui/type-alias-impl-trait/issue-57700.stderr
index c701e3e..dc6be87 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57700.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57700.stderr
@@ -1,5 +1,5 @@
 error: type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-57700.rs:16:58
+  --> $DIR/issue-57700.rs:17:58
    |
 LL |       fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
    |  __________________________________________________________^
diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs
index 50b9d1a..14d2141 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60371.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs
@@ -1,3 +1,5 @@
+// ignore-compare-mode-chalk
+
 trait Bug {
     type Item: Bug;
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
index bf2d612..d8e514a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/issue-60371.rs:8:17
+  --> $DIR/issue-60371.rs:10:17
    |
 LL |     type Item = impl Bug;
    |                 ^^^^^^^^
@@ -8,17 +8,16 @@
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `(): Bug` is not satisfied
-  --> $DIR/issue-60371.rs:8:17
+  --> $DIR/issue-60371.rs:10:17
    |
 LL |     type Item = impl Bug;
    |                 ^^^^^^^^ the trait `Bug` is not implemented for `()`
    |
    = help: the following implementations were found:
              <&() as Bug>
-   = note: the return type of a function must have a statically known size
 
 error: could not find defining uses
-  --> $DIR/issue-60371.rs:8:17
+  --> $DIR/issue-60371.rs:10:17
    |
 LL |     type Item = impl Bug;
    |                 ^^^^^^^^
diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
index 9ad181b..8615b3f 100644
--- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
@@ -6,7 +6,6 @@
    |
    = note: expected opaque type `impl FnOnce<()>`
                 found unit type `()`
-   = note: the return type of a function must have a statically known size
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-74244.rs b/src/test/ui/type-alias-impl-trait/issue-74244.rs
new file mode 100644
index 0000000..bb4104b
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-74244.rs
@@ -0,0 +1,20 @@
+#![feature(type_alias_impl_trait)]
+
+trait Allocator {
+    type Buffer;
+}
+
+struct DefaultAllocator;
+
+impl<T> Allocator for DefaultAllocator {
+    //~^ ERROR: the type parameter `T` is not constrained
+    type Buffer = ();
+}
+
+type A = impl Fn(<DefaultAllocator as Allocator>::Buffer);
+
+fn foo() -> A {
+    |_| ()
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-74244.stderr b/src/test/ui/type-alias-impl-trait/issue-74244.stderr
new file mode 100644
index 0000000..ff6bacd
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-74244.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-74244.rs:9:6
+   |
+LL | impl<T> Allocator for DefaultAllocator {
+   |      ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.rs b/src/test/ui/type-alias-impl-trait/issue-74761.rs
new file mode 100644
index 0000000..4345b5d
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-74761.rs
@@ -0,0 +1,16 @@
+#![feature(member_constraints)]
+#![feature(type_alias_impl_trait)]
+
+pub trait A {
+    type B;
+    fn f(&self) -> Self::B;
+}
+impl<'a, 'b> A for () {
+    //~^ ERROR the lifetime parameter `'a` is not constrained
+    //~| ERROR the lifetime parameter `'b` is not constrained
+    type B = impl core::fmt::Debug;
+
+    fn f(&self) -> Self::B {}
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.stderr
new file mode 100644
index 0000000..3f38fa4
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-74761.stderr
@@ -0,0 +1,15 @@
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-74761.rs:8:6
+   |
+LL | impl<'a, 'b> A for () {
+   |      ^^ unconstrained lifetime parameter
+
+error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-74761.rs:8:10
+   |
+LL | impl<'a, 'b> A for () {
+   |          ^^ unconstrained lifetime parameter
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs
index 02485b2..f29b980 100644
--- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs
+++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs
@@ -7,6 +7,7 @@
 type Two<T, U> = impl Debug;
 
 fn two<T: Debug>(t: T) -> Two<T, u32> {
+    //~^ ERROR non-defining opaque type use in defining scope
     (t, 4i8)
 }
 
@@ -24,9 +25,7 @@
     const FOO: i32 = 42;
 }
 
-// this should work! But it requires `two` and `three` not to be defining uses,
-// just restricting uses
-fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> { //~ concrete type differs from previous
+fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
     (t, <U as Bar>::FOO)
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr
index 9ce07a8..2fa236b 100644
--- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr
+++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr
@@ -1,14 +1,14 @@
-error: concrete type differs from previous defining opaque type use
-  --> $DIR/not_a_defining_use.rs:29:1
-   |
-LL | fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
-   |
-note: previous use here
-  --> $DIR/not_a_defining_use.rs:9:1
+error: non-defining opaque type use in defining scope
+  --> $DIR/not_a_defining_use.rs:9:27
    |
 LL | fn two<T: Debug>(t: T) -> Two<T, u32> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                           ^^^^^^^^^^^
+   |
+note: used non-generic type `u32` for generic parameter
+  --> $DIR/not_a_defining_use.rs:7:13
+   |
+LL | type Two<T, U> = impl Debug;
+   |             ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
index d508356..58f0f5b 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn, type_alias_impl_trait)]
+#![feature(const_impl_trait, type_alias_impl_trait)]
 
 type Bar = impl Send;
 
diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs
index a3ff4ad..74ffa60 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn, type_alias_impl_trait)]
+#![feature(const_impl_trait, type_alias_impl_trait)]
 
 type Foo = impl Send;
 
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs
new file mode 100644
index 0000000..efbf4f1
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs
@@ -0,0 +1,18 @@
+// regression test for #74018
+
+#![feature(type_alias_impl_trait)]
+
+trait Trait {
+    type Associated;
+    fn into(self) -> Self::Associated;
+}
+
+impl<'a, I: Iterator<Item = i32>> Trait for (i32, I) {
+    //~^ ERROR the lifetime parameter `'a` is not constrained
+    type Associated = (i32, impl Iterator<Item = i32>);
+    fn into(self) -> Self::Associated {
+        (0_i32, [0_i32].iter().copied())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr
new file mode 100644
index 0000000..8cdce2f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/type-alias-impl-trait-unconstrained-lifetime.rs:10:6
+   |
+LL | impl<'a, I: Iterator<Item = i32>> Trait for (i32, I) {
+   |      ^^ unconstrained lifetime parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
index 209134a..80192d1 100644
--- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
+++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait.rs
@@ -70,14 +70,14 @@
 }
 
 trait Trait {}
-type GenericBound<'a, T: Trait> = impl Sized + 'a;
+type GenericBound<'a, T: Trait + 'a> = impl Sized + 'a;
 
 fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
     t
 }
 
 mod pass_through {
-    pub type Passthrough<T> = impl Sized + 'static;
+    pub type Passthrough<T: 'static> = impl Sized + 'static;
 
     fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
         t
diff --git a/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr b/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
index 5391899..2de5f6e 100644
--- a/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
+++ b/src/test/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr
@@ -13,15 +13,17 @@
 error[E0038]: the trait `MyAdd` cannot be made into an object
   --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:14:18
    |
-LL | trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; }
-   |       -----                                           ---- ...because method `add` references the `Self` type in its return type
-   |       |
-   |       this trait cannot be made into an object...
-...
 LL |     let y = x as dyn MyAdd<i32>;
-   |                  ^^^^^^^^^^^^^^ the trait `MyAdd` cannot be made into an object
+   |                  ^^^^^^^^^^^^^^ `MyAdd` cannot be made into an object
    |
    = help: consider moving `add` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:6:55
+   |
+LL | trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; }
+   |       -----                                           ^^^^ ...because method `add` references the `Self` type in its return type
+   |       |
+   |       this trait cannot be made into an object...
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
index 48ff1a2..684f451 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
@@ -405,15 +405,10 @@
    |              ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:43:27
+  --> $DIR/typeck_type_placeholder_item.rs:182:21
    |
-LL |     fn test10(&self, _x : _) { }
-   |                           ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL |     fn test10<T>(&self, _x : T) { }
-   |              ^^^             ^
+LL | type Y = impl Trait<_>;
+   |                     ^ not allowed in type signatures
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:140:31
@@ -486,45 +481,6 @@
    |                      ^^^      ^
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:61:37
-   |
-LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
-   |                                     ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
-   |                  ^^^                   ^
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:110:34
-   |
-LL |         fn fn_test10(&self, _x : _) { }
-   |                                  ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL |         fn fn_test10<T>(&self, _x : T) { }
-   |                     ^^^             ^
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:118:41
-   |
-LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
-   |                                         ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
-   |                      ^^^                   ^
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
-  --> $DIR/typeck_type_placeholder_item.rs:182:21
-   |
-LL | type Y = impl Trait<_>;
-   |                     ^ not allowed in type signatures
-
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:190:14
    |
 LL |     type B = _;
@@ -561,6 +517,17 @@
    |                        help: replace with the correct return type: `()`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:43:27
+   |
+LL |     fn test10(&self, _x : _) { }
+   |                           ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |     fn test10<T>(&self, _x : T) { }
+   |              ^^^             ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:58:24
    |
 LL |     fn clone(&self) -> _ { Test9 }
@@ -570,6 +537,17 @@
    |                        help: replace with the correct return type: `Test9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:61:37
+   |
+LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
+   |                                     ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
+   |                  ^^^                   ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:107:31
    |
 LL |         fn fn_test9(&self) -> _ { () }
@@ -579,6 +557,17 @@
    |                               help: replace with the correct return type: `()`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:110:34
+   |
+LL |         fn fn_test10(&self, _x : _) { }
+   |                                  ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |         fn fn_test10<T>(&self, _x : T) { }
+   |                     ^^^             ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:115:28
    |
 LL |         fn clone(&self) -> _ { FnTest9 }
@@ -588,6 +577,17 @@
    |                            help: replace with the correct return type: `FnTest9`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/typeck_type_placeholder_item.rs:118:41
+   |
+LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
+   |                                         ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
+   |                      ^^^                   ^
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type A = _;
diff --git a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr
index 9e710c1..a2bf963 100644
--- a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr
+++ b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr
@@ -5,6 +5,7 @@
    |     ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32`
    |
    = help: the trait `Add<u32>` is not implemented for `i32`
+   = note: required by `add`
 
 error[E0308]: mismatched types
   --> $DIR/ufcs-qpath-self-mismatch.rs:6:28
diff --git a/src/test/ui/unboxed-closures/issue-53448.rs b/src/test/ui/unboxed-closures/issue-53448.rs
new file mode 100644
index 0000000..5c82a56
--- /dev/null
+++ b/src/test/ui/unboxed-closures/issue-53448.rs
@@ -0,0 +1,15 @@
+#![feature(unboxed_closures)]
+
+trait Lt<'a> {
+    type T;
+}
+impl<'a> Lt<'a> for () {
+    type T = ();
+}
+
+fn main() {
+    let v: <() as Lt<'_>>::T = ();
+    let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
+    //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known
+    f(v);
+}
diff --git a/src/test/ui/unboxed-closures/issue-53448.stderr b/src/test/ui/unboxed-closures/issue-53448.stderr
new file mode 100644
index 0000000..bece9ee
--- /dev/null
+++ b/src/test/ui/unboxed-closures/issue-53448.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time
+  --> $DIR/issue-53448.rs:12:54
+   |
+LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
+   |                                                      ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T`
+   = help: unsized locals are gated as an unstable feature
+help: consider further restricting the associated type
+   |
+LL | fn main() where <() as Lt<'_>>::T: Sized {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {};
+   |                                                         ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.rs b/src/test/ui/uninhabited/uninhabited-enum-cast.rs
index 7e178e0..5a75c94 100644
--- a/src/test/ui/uninhabited/uninhabited-enum-cast.rs
+++ b/src/test/ui/uninhabited/uninhabited-enum-cast.rs
@@ -1,7 +1,9 @@
+// check-pass
+
 enum E {}
 
 fn f(e: E) {
-    println!("{}", (e as isize).to_string());   //~ ERROR non-primitive cast
+    println!("{}", (e as isize).to_string());
 }
 
 fn main() {}
diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
deleted file mode 100644
index a9f10df..0000000
--- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0605]: non-primitive cast: `E` as `isize`
-  --> $DIR/uninhabited-enum-cast.rs:4:20
-   |
-LL |     println!("{}", (e as isize).to_string());
-   |                    ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0605`.
diff --git a/src/test/ui/union/union-align.rs b/src/test/ui/union/union-align.rs
index edd83a5..1340ae4 100644
--- a/src/test/ui/union/union-align.rs
+++ b/src/test/ui/union/union-align.rs
@@ -1,8 +1,6 @@
 // run-pass
 #![allow(dead_code)]
 
-#![feature(untagged_unions)]
-
 use std::mem::{size_of, size_of_val, align_of, align_of_val};
 
 #[repr(align(16))]
@@ -35,6 +33,7 @@
     use std::mem::{size_of, align_of};
 
     #[repr(align(16))]
+    #[derive(Copy, Clone)]
     struct S1 {
         a: u16,
         b: u8,
diff --git a/src/test/ui/union/union-copy.rs b/src/test/ui/union/union-copy.rs
index 8318f96..5c3f8d9 100644
--- a/src/test/ui/union/union-copy.rs
+++ b/src/test/ui/union/union-copy.rs
@@ -1,5 +1,3 @@
-#![feature(untagged_unions)]
-
 #[derive(Clone)]
 union U {
     a: u8
@@ -7,7 +5,7 @@
 
 #[derive(Clone)]
 union W {
-    a: String
+    a: std::mem::ManuallyDrop<String>
 }
 
 impl Copy for U {} // OK
diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr
index a875ff6..0f47bae 100644
--- a/src/test/ui/union/union-copy.stderr
+++ b/src/test/ui/union/union-copy.stderr
@@ -1,8 +1,8 @@
 error[E0204]: the trait `Copy` may not be implemented for this type
-  --> $DIR/union-copy.rs:14:6
+  --> $DIR/union-copy.rs:12:6
    |
-LL |     a: String
-   |     --------- this field does not implement `Copy`
+LL |     a: std::mem::ManuallyDrop<String>
+   |     --------------------------------- this field does not implement `Copy`
 ...
 LL | impl Copy for W {}
    |      ^^^^
diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr
index fb16649..f772276 100644
--- a/src/test/ui/union/union-deref.stderr
+++ b/src/test/ui/union/union-deref.stderr
@@ -29,7 +29,7 @@
   --> $DIR/union-deref.rs:23:14
    |
 LL |     unsafe { u.f.0.0 = Vec::new() };
-   |              ^^^^^^^
+   |              ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
@@ -38,7 +38,7 @@
   --> $DIR/union-deref.rs:25:19
    |
 LL |     unsafe { &mut u.f.0.0 };
-   |                   ^^^^^^^
+   |                   ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
@@ -47,7 +47,7 @@
   --> $DIR/union-deref.rs:27:14
    |
 LL |     unsafe { u.f.0.0.push(0) };
-   |              ^^^^^^^
+   |              ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs
index 8126980..753a9f7 100644
--- a/src/test/ui/union/union-derive-clone.rs
+++ b/src/test/ui/union/union-derive-clone.rs
@@ -1,5 +1,3 @@
-#![feature(untagged_unions)]
-
 use std::mem::ManuallyDrop;
 
 #[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied
diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr
index 7a59f53..e18f457 100644
--- a/src/test/ui/union/union-derive-clone.stderr
+++ b/src/test/ui/union/union-derive-clone.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `U1: Copy` is not satisfied
-  --> $DIR/union-derive-clone.rs:5:10
+  --> $DIR/union-derive-clone.rs:3:10
    |
 LL | #[derive(Clone)]
    |          ^^^^^ the trait `Copy` is not implemented for `U1`
@@ -12,7 +12,7 @@
    = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0599]: no method named `clone` found for union `U5<CloneNoCopy>` in the current scope
-  --> $DIR/union-derive-clone.rs:37:15
+  --> $DIR/union-derive-clone.rs:35:15
    |
 LL | union U5<T> {
    | -----------
diff --git a/src/test/ui/union/union-derive-eq.rs b/src/test/ui/union/union-derive-eq.rs
index ac5808e..e689f8c 100644
--- a/src/test/ui/union/union-derive-eq.rs
+++ b/src/test/ui/union/union-derive-eq.rs
@@ -1,5 +1,3 @@
-#![feature(untagged_unions)]
-
 #[derive(Eq)] // OK
 union U1 {
     a: u8,
@@ -7,7 +5,7 @@
 
 impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Copy, Clone)]
 struct PartialEqNotEq;
 
 #[derive(Eq)]
diff --git a/src/test/ui/union/union-derive-eq.stderr b/src/test/ui/union/union-derive-eq.stderr
index c4d437c..0591d12 100644
--- a/src/test/ui/union/union-derive-eq.stderr
+++ b/src/test/ui/union/union-derive-eq.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied
-  --> $DIR/union-derive-eq.rs:15:5
+  --> $DIR/union-derive-eq.rs:13:5
    |
 LL |     a: PartialEqNotEq,
    |     ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq`
diff --git a/src/test/ui/union/union-derive-rpass.rs b/src/test/ui/union/union-derive-rpass.rs
index b2f7ae6..db18a81 100644
--- a/src/test/ui/union/union-derive-rpass.rs
+++ b/src/test/ui/union/union-derive-rpass.rs
@@ -4,8 +4,6 @@
 
 // Some traits can be derived for unions.
 
-#![feature(untagged_unions)]
-
 #[derive(
     Copy,
     Clone,
diff --git a/src/test/ui/union/union-drop-assign.rs b/src/test/ui/union/union-drop-assign.rs
index f1511b0..215666b 100644
--- a/src/test/ui/union/union-drop-assign.rs
+++ b/src/test/ui/union/union-drop-assign.rs
@@ -3,8 +3,6 @@
 
 // Drop works for union itself.
 
-#![feature(untagged_unions)]
-
 use std::mem::ManuallyDrop;
 
 struct S;
diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs
index 4df3ed5..9edf582 100644
--- a/src/test/ui/union/union-drop.rs
+++ b/src/test/ui/union/union-drop.rs
@@ -4,8 +4,7 @@
 
 // Drop works for union itself.
 
-#![feature(untagged_unions)]
-
+#[derive(Copy, Clone)]
 struct S;
 
 union U {
diff --git a/src/test/ui/union/union-generic-rpass.rs b/src/test/ui/union/union-generic-rpass.rs
index eb169c5..69837f3 100644
--- a/src/test/ui/union/union-generic-rpass.rs
+++ b/src/test/ui/union/union-generic-rpass.rs
@@ -1,8 +1,6 @@
 // run-pass
 #![allow(dead_code)]
 
-#![feature(untagged_unions)]
-
 use std::mem::ManuallyDrop;
 
 union MaybeItem<T: Iterator> {
@@ -16,7 +14,7 @@
 }
 
 unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy {
-    U { a: a }.b
+    U { a }.b
 }
 
 fn main() {
diff --git a/src/test/ui/union/union-manuallydrop-rpass.rs b/src/test/ui/union/union-manuallydrop-rpass.rs
index a43a505..977d12f 100644
--- a/src/test/ui/union/union-manuallydrop-rpass.rs
+++ b/src/test/ui/union/union-manuallydrop-rpass.rs
@@ -1,4 +1,3 @@
-#![feature(untagged_unions)]
 #![allow(dead_code)]
 // run-pass
 
diff --git a/src/test/ui/union/union-nodrop.rs b/src/test/ui/union/union-nodrop.rs
index 59282be..bc58c59 100644
--- a/src/test/ui/union/union-nodrop.rs
+++ b/src/test/ui/union/union-nodrop.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(untagged_unions)]
-
 #![allow(dead_code)]
 
 use std::mem::needs_drop;
diff --git a/src/test/ui/union/union-overwrite.rs b/src/test/ui/union/union-overwrite.rs
index 8234beb..399ed9a 100644
--- a/src/test/ui/union/union-overwrite.rs
+++ b/src/test/ui/union/union-overwrite.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(untagged_unions)]
 
 #[repr(C)]
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/union/union-packed.rs b/src/test/ui/union/union-packed.rs
index ceb35d9..9cde44c 100644
--- a/src/test/ui/union/union-packed.rs
+++ b/src/test/ui/union/union-packed.rs
@@ -2,8 +2,6 @@
 #![allow(dead_code)]
 #![allow(non_snake_case)]
 
-#![feature(untagged_unions)]
-
 use std::mem::{size_of, size_of_val, align_of, align_of_val};
 
 struct S {
@@ -118,6 +116,7 @@
     use std::mem::{size_of, align_of};
 
     #[repr(packed)]
+    #[derive(Copy, Clone)]
     struct S1 {
         a: u16,
         b: u8,
diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs
index 8535cbd..10f0c46 100644
--- a/src/test/ui/union/union-unsafe.rs
+++ b/src/test/ui/union/union-unsafe.rs
@@ -1,4 +1,3 @@
-#![feature(untagged_unions)]
 use std::mem::ManuallyDrop;
 
 union U1 {
diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr
index e020dab..b50d9e1 100644
--- a/src/test/ui/union/union-unsafe.stderr
+++ b/src/test/ui/union/union-unsafe.stderr
@@ -1,5 +1,5 @@
 error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:22:5
+  --> $DIR/union-unsafe.rs:21:5
    |
 LL |     u3.a = ManuallyDrop::new(T::default());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
@@ -7,7 +7,7 @@
    = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:23:6
+  --> $DIR/union-unsafe.rs:22:6
    |
 LL |     *u3.a = T::default();
    |      ^^^^ access to union field
@@ -15,7 +15,7 @@
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:29:6
+  --> $DIR/union-unsafe.rs:28:6
    |
 LL |     *u3.a = T::default();
    |      ^^^^ access to union field
@@ -23,7 +23,7 @@
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:37:13
+  --> $DIR/union-unsafe.rs:36:13
    |
 LL |     let a = u1.a;
    |             ^^^^ access to union field
@@ -31,7 +31,7 @@
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:40:14
+  --> $DIR/union-unsafe.rs:39:14
    |
 LL |     let U1 { a } = u1;
    |              ^ access to union field
@@ -39,7 +39,7 @@
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:41:20
+  --> $DIR/union-unsafe.rs:40:20
    |
 LL |     if let U1 { a: 12 } = u1 {}
    |                    ^^ access to union field
@@ -47,7 +47,7 @@
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:45:5
+  --> $DIR/union-unsafe.rs:44:5
    |
 LL |     u2.a = ManuallyDrop::new(String::from("new"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
@@ -55,7 +55,7 @@
    = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:46:6
+  --> $DIR/union-unsafe.rs:45:6
    |
 LL |     *u2.a = String::from("new");
    |      ^^^^ access to union field
@@ -63,7 +63,7 @@
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:50:6
+  --> $DIR/union-unsafe.rs:49:6
    |
 LL |     *u3.a = 1;
    |      ^^^^ access to union field
@@ -71,7 +71,7 @@
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:53:5
+  --> $DIR/union-unsafe.rs:52:5
    |
 LL |     u3.a = ManuallyDrop::new(String::from("new"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
@@ -79,7 +79,7 @@
    = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:54:6
+  --> $DIR/union-unsafe.rs:53:6
    |
 LL |     *u3.a = String::from("new");
    |      ^^^^ access to union field
diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr
index 1a6bcd3..5ce4296 100644
--- a/src/test/ui/unsafe/ranged_ints2_const.stderr
+++ b/src/test/ui/unsafe/ranged_ints2_const.stderr
@@ -1,17 +1,17 @@
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/ranged_ints2_const.rs:11:9
+  --> $DIR/ranged_ints2_const.rs:11:13
    |
 LL |     let y = &mut x.0;
-   |         ^
+   |             ^^^^^^^^
    |
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/ranged_ints2_const.rs:18:9
+  --> $DIR/ranged_ints2_const.rs:18:22
    |
 LL |     let y = unsafe { &mut x.0 };
-   |         ^
+   |                      ^^^^^^^^
    |
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
diff --git a/src/test/ui/unsigned-literal-negation.rs b/src/test/ui/unsigned-literal-negation.rs
new file mode 100644
index 0000000..943c7f7
--- /dev/null
+++ b/src/test/ui/unsigned-literal-negation.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let x = -1 as usize; //~ ERROR: cannot apply unary operator `-`
+    let x = (-1) as usize; //~ ERROR: cannot apply unary operator `-`
+    let x: u32 = -1; //~ ERROR: cannot apply unary operator `-`
+}
diff --git a/src/test/ui/unsigned-literal-negation.stderr b/src/test/ui/unsigned-literal-negation.stderr
new file mode 100644
index 0000000..0aaa8c3
--- /dev/null
+++ b/src/test/ui/unsigned-literal-negation.stderr
@@ -0,0 +1,36 @@
+error[E0600]: cannot apply unary operator `-` to type `usize`
+  --> $DIR/unsigned-literal-negation.rs:2:13
+   |
+LL |     let x = -1 as usize;
+   |             ^^
+   |             |
+   |             cannot apply unary operator `-`
+   |             help: you may have meant the maximum value of `usize`: `usize::MAX`
+   |
+   = note: unsigned values cannot be negated
+
+error[E0600]: cannot apply unary operator `-` to type `usize`
+  --> $DIR/unsigned-literal-negation.rs:3:13
+   |
+LL |     let x = (-1) as usize;
+   |             ^^^^
+   |             |
+   |             cannot apply unary operator `-`
+   |             help: you may have meant the maximum value of `usize`: `usize::MAX`
+   |
+   = note: unsigned values cannot be negated
+
+error[E0600]: cannot apply unary operator `-` to type `u32`
+  --> $DIR/unsigned-literal-negation.rs:4:18
+   |
+LL |     let x: u32 = -1;
+   |                  ^^
+   |                  |
+   |                  cannot apply unary operator `-`
+   |                  help: you may have meant the maximum value of `u32`: `u32::MAX`
+   |
+   = note: unsigned values cannot be negated
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0600`.
diff --git a/src/test/ui/unsized/issue-71659.rs b/src/test/ui/unsized/issue-71659.rs
new file mode 100644
index 0000000..3524ca0
--- /dev/null
+++ b/src/test/ui/unsized/issue-71659.rs
@@ -0,0 +1,32 @@
+#![feature(unsize)]
+
+use std::marker::Unsize;
+
+pub trait CastTo<T: ?Sized>: Unsize<T> {
+    fn cast_to(&self) -> &T;
+}
+
+impl<T: ?Sized, U: ?Sized + Unsize<T>> CastTo<T> for U {
+    fn cast_to(&self) -> &T {
+        self
+    }
+}
+
+impl<T: ?Sized> Cast for T {}
+pub trait Cast {
+    fn cast<T: ?Sized>(&self) -> &T
+    where
+        Self: CastTo<T>,
+    {
+        self
+    }
+}
+
+pub trait Foo: CastTo<[i32]> {}
+impl Foo for [i32; 0] {}
+
+fn main() {
+    let x: &dyn Foo = &[];
+    let x = x.cast::<[i32]>();
+    //~^ ERROR: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied
+}
diff --git a/src/test/ui/unsized/issue-71659.stderr b/src/test/ui/unsized/issue-71659.stderr
new file mode 100644
index 0000000..be2df8c
--- /dev/null
+++ b/src/test/ui/unsized/issue-71659.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied
+  --> $DIR/issue-71659.rs:30:15
+   |
+LL |     let x = x.cast::<[i32]>();
+   |               ^^^^ the trait `CastTo<[i32]>` is not implemented for `dyn Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unsized/issue-75707.rs b/src/test/ui/unsized/issue-75707.rs
new file mode 100644
index 0000000..9f04cdb
--- /dev/null
+++ b/src/test/ui/unsized/issue-75707.rs
@@ -0,0 +1,17 @@
+pub trait Callback {
+    fn cb();
+}
+
+pub trait Processing {
+    type Call: Callback;
+}
+
+fn f<P: Processing + ?Sized>() {
+    P::Call::cb();
+}
+
+fn main() {
+    struct MyCall;
+    f::<dyn Processing<Call = MyCall>>();
+    //~^ ERROR: the trait bound `MyCall: Callback` is not satisfied
+}
diff --git a/src/test/ui/unsized/issue-75707.stderr b/src/test/ui/unsized/issue-75707.stderr
new file mode 100644
index 0000000..6e557a2
--- /dev/null
+++ b/src/test/ui/unsized/issue-75707.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `MyCall: Callback` is not satisfied
+  --> $DIR/issue-75707.rs:15:5
+   |
+LL | fn f<P: Processing + ?Sized>() {
+   |         ---------- required by this bound in `f`
+...
+LL |     f::<dyn Processing<Call = MyCall>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Callback` is not implemented for `MyCall`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/usize-generic-argument-parent.rs b/src/test/ui/usize-generic-argument-parent.rs
new file mode 100644
index 0000000..46b06e2
--- /dev/null
+++ b/src/test/ui/usize-generic-argument-parent.rs
@@ -0,0 +1,5 @@
+fn foo() {
+    let x: usize<foo>; //~ ERROR const arguments are not allowed for this type
+}
+
+fn main() {}
diff --git a/src/test/ui/usize-generic-argument-parent.stderr b/src/test/ui/usize-generic-argument-parent.stderr
new file mode 100644
index 0000000..f1eae3b
--- /dev/null
+++ b/src/test/ui/usize-generic-argument-parent.stderr
@@ -0,0 +1,9 @@
+error[E0109]: const arguments are not allowed for this type
+  --> $DIR/usize-generic-argument-parent.rs:2:18
+   |
+LL |     let x: usize<foo>;
+   |                  ^^^ const argument not allowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0109`.
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr
index e707839..29dfb58 100644
--- a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr
@@ -1,42 +1,48 @@
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-convert-unsafe-trait-obj-box.rs:16:33
    |
+LL |     let t_box: Box<dyn Trait> = Box::new(S);
+   |                                 ^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     let t_box: Box<dyn Trait> = Box::new(S);
-   |                                 ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Trait>>` for `Box<S>`
    = note: required by cast to type `Box<dyn Trait>`
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15
    |
+LL |     takes_box(Box::new(S));
+   |               ^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     takes_box(Box::new(S));
-   |               ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Trait>>` for `Box<S>`
    = note: required by cast to type `Box<(dyn Trait + 'static)>`
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5
    |
+LL |     Box::new(S) as Box<dyn Trait>;
+   |     ^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     Box::new(S) as Box<dyn Trait>;
-   |     ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Trait>>` for `Box<S>`
    = note: required by cast to type `Box<dyn Trait>`
 
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr
index 08d4808..02169f2 100644
--- a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr
@@ -1,42 +1,48 @@
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-convert-unsafe-trait-obj.rs:16:25
    |
+LL |     let t: &dyn Trait = &S;
+   |                         ^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     let t: &dyn Trait = &S;
-   |                         ^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S`
    = note: required by cast to type `&dyn Trait`
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-convert-unsafe-trait-obj.rs:17:17
    |
+LL |     takes_trait(&S);
+   |                 ^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     takes_trait(&S);
-   |                 ^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S`
    = note: required by cast to type `&dyn Trait`
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-convert-unsafe-trait-obj.rs:15:5
    |
+LL |     &S as &dyn Trait;
+   |     ^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     &S as &dyn Trait;
-   |     ^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S`
    = note: required by cast to type `&dyn Trait`
 
diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr
index e7921f3..988cb2f 100644
--- a/src/test/ui/wf/wf-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-fn-where-clause.stderr
@@ -34,9 +34,10 @@
   --> $DIR/wf-fn-where-clause.rs:12:16
    |
 LL | fn bar() where Vec<dyn Copy>:, {}
-   |                ^^^^^^^^^^^^^ the trait `Copy` cannot be made into an object
+   |                ^^^^^^^^^^^^^ `Copy` cannot be made into an object
    |
    = note: the trait cannot be made into an object because it requires `Self: Sized`
+   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/wf/wf-object-safe.stderr b/src/test/ui/wf/wf-object-safe.stderr
index 8935d76..9b749f8 100644
--- a/src/test/ui/wf/wf-object-safe.stderr
+++ b/src/test/ui/wf/wf-object-safe.stderr
@@ -1,15 +1,17 @@
 error[E0038]: the trait `A` cannot be made into an object
   --> $DIR/wf-object-safe.rs:9:13
    |
+LL |     let _x: &dyn A;
+   |             ^^^^^^ `A` cannot be made into an object
+   |
+   = help: consider moving `foo` to another trait
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-object-safe.rs:5:23
+   |
 LL | trait A {
    |       - this trait cannot be made into an object...
 LL |     fn foo(&self, _x: &Self);
-   |                       ----- ...because method `foo` references the `Self` type in this parameter
-...
-LL |     let _x: &dyn A;
-   |             ^^^^^^ the trait `A` cannot be made into an object
-   |
-   = help: consider moving `foo` to another trait
+   |                       ^^^^^ ...because method `foo` references the `Self` type in this parameter
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
index d0f43f8..9dbd41c 100644
--- a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
+++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
@@ -15,28 +15,32 @@
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-unsafe-trait-obj-match.rs:26:21
    |
+LL |         Some(()) => &S,
+   |                     ^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-unsafe-trait-obj-match.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |         Some(()) => &S,
-   |                     ^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S`
    = note: required by cast to type `&dyn Trait`
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-unsafe-trait-obj-match.rs:25:25
    |
+LL |     let t: &dyn Trait = match opt() {
+   |                         ^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/wf-unsafe-trait-obj-match.rs:6:14
+   |
 LL | trait Trait: Sized {}
-   |       -----  ----- ...because it requires `Self: Sized`
+   |       -----  ^^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait cannot be made into an object...
-...
-LL |     let t: &dyn Trait = match opt() {
-   |                         ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
-   |
    = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&R`
    = note: required by cast to type `&dyn Trait`
 
diff --git a/src/test/ui/wrapping-int-combinations.rs b/src/test/ui/wrapping-int-combinations.rs
deleted file mode 100644
index f0bc479..0000000
--- a/src/test/ui/wrapping-int-combinations.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-// run-pass
-
-use std::num::Wrapping;
-
-macro_rules! wrapping_operation {
-    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
-        assert_eq!($result, $lhs $op $rhs);
-        assert_eq!($result, &$lhs $op $rhs);
-        assert_eq!($result, $lhs $op &$rhs);
-        assert_eq!($result, &$lhs $op &$rhs);
-    };
-    ($result:expr, $op:tt $expr:expr) => {
-        assert_eq!($result, $op $expr);
-        assert_eq!($result, $op &$expr);
-    };
-}
-
-macro_rules! wrapping_assignment {
-    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
-        let mut lhs1 = $lhs;
-        lhs1 $op $rhs;
-        assert_eq!($result, lhs1);
-
-        let mut lhs2 = $lhs;
-        lhs2 $op &$rhs;
-        assert_eq!($result, lhs2);
-    };
-}
-
-macro_rules! wrapping_test {
-    ($type:ty, $min:expr, $max:expr) => {
-        let zero: Wrapping<$type> = Wrapping(0);
-        let one: Wrapping<$type> = Wrapping(1);
-        let min: Wrapping<$type> = Wrapping($min);
-        let max: Wrapping<$type> = Wrapping($max);
-
-        wrapping_operation!(min, max + one);
-        wrapping_assignment!(min, max += one);
-        wrapping_operation!(max, min - one);
-        wrapping_assignment!(max, min -= one);
-        wrapping_operation!(max, max * one);
-        wrapping_assignment!(max, max *= one);
-        wrapping_operation!(max, max / one);
-        wrapping_assignment!(max, max /= one);
-        wrapping_operation!(zero, max % one);
-        wrapping_assignment!(zero, max %= one);
-        wrapping_operation!(zero, zero & max);
-        wrapping_assignment!(zero, zero &= max);
-        wrapping_operation!(max, zero | max);
-        wrapping_assignment!(max, zero |= max);
-        wrapping_operation!(zero, max ^ max);
-        wrapping_assignment!(zero, max ^= max);
-        wrapping_operation!(zero, zero << 1usize);
-        wrapping_assignment!(zero, zero <<= 1usize);
-        wrapping_operation!(zero, zero >> 1usize);
-        wrapping_assignment!(zero, zero >>= 1usize);
-        wrapping_operation!(zero, -zero);
-        wrapping_operation!(max, !min);
-    };
-}
-
-fn main() {
-    wrapping_test!(i8, std::i8::MIN, std::i8::MAX);
-    wrapping_test!(i16, std::i16::MIN, std::i16::MAX);
-    wrapping_test!(i32, std::i32::MIN, std::i32::MAX);
-    wrapping_test!(i64, std::i64::MIN, std::i64::MAX);
-    #[cfg(not(target_os = "emscripten"))]
-    wrapping_test!(i128, std::i128::MIN, std::i128::MAX);
-    wrapping_test!(isize, std::isize::MIN, std::isize::MAX);
-    wrapping_test!(u8, std::u8::MIN, std::u8::MAX);
-    wrapping_test!(u16, std::u16::MIN, std::u16::MAX);
-    wrapping_test!(u32, std::u32::MIN, std::u32::MAX);
-    wrapping_test!(u64, std::u64::MIN, std::u64::MAX);
-    #[cfg(not(target_os = "emscripten"))]
-    wrapping_test!(u128, std::u128::MIN, std::u128::MAX);
-    wrapping_test!(usize, std::usize::MIN, std::usize::MAX);
-}
diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr
index c1274bd..5498dae 100644
--- a/src/test/ui/wrong-ret-type.stderr
+++ b/src/test/ui/wrong-ret-type.stderr
@@ -6,7 +6,7 @@
    |                |
    |                expected `usize` because of return type
    |
-help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit
    |
 LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); }
    |                                                 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml
index 0bbbabd..4a2c710 100644
--- a/src/tools/build-manifest/Cargo.toml
+++ b/src/tools/build-manifest/Cargo.toml
@@ -8,3 +8,10 @@
 toml = "0.5"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
+anyhow = "1.0.32"
+flate2 = "1.0.16"
+tar = "0.4.29"
+sha2 = "0.9.1"
+rayon = "1.3.1"
+hex = "0.4.2"
+num_cpus = "1.13.0"
diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md
index a80f36d..b77c5a9 100644
--- a/src/tools/build-manifest/README.md
+++ b/src/tools/build-manifest/README.md
@@ -20,11 +20,9 @@
 `path/to/output` with:
 
 ```
-$ BUILD_MANIFEST_DISABLE_SIGNING=1 cargo +nightly run \
-    path/to/dist path/to/output 1970-01-01 \
-    nightly nightly nightly nightly nightly nightly nightly nightly \
-    http://example.com
+$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \
+    CHANNEL VERSION
 ```
 
-In the future, if the tool complains about missing arguments just add more
-`nightly`s in the middle.
+Remember to replace `CHANNEL` with the channel you produced dist artifacts of
+and `VERSION` with the current Rust version.
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 125f2d1..1b78011 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -4,17 +4,26 @@
 //! via `x.py dist hash-and-sign`; the cmdline arguments are set up
 //! by rustbuild (in `src/bootstrap/dist.rs`).
 
-use serde::Serialize;
+mod manifest;
+mod versions;
 
-use std::collections::BTreeMap;
-use std::collections::HashMap;
+use crate::manifest::{Component, FileHash, Manifest, Package, Rename, Target};
+use crate::versions::{PkgType, Versions};
+use rayon::prelude::*;
+use sha2::Digest;
+use std::collections::{BTreeMap, HashMap, HashSet};
 use std::env;
+use std::error::Error;
 use std::fs::{self, File};
-use std::io::{self, Read, Write};
+use std::io::{self, BufReader, Read, Write};
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
+use std::sync::Mutex;
+use std::time::Instant;
 
 static HOSTS: &[&str] = &[
+    "aarch64-apple-darwin",
+    "aarch64-pc-windows-msvc",
     "aarch64-unknown-linux-gnu",
     "aarch64-unknown-linux-musl",
     "arm-unknown-linux-gnueabi",
@@ -48,6 +57,7 @@
 ];
 
 static TARGETS: &[&str] = &[
+    "aarch64-apple-darwin",
     "aarch64-apple-ios",
     "aarch64-fuchsia",
     "aarch64-linux-android",
@@ -165,57 +175,6 @@
 
 static NIGHTLY_ONLY_COMPONENTS: &[&str] = &["miri-preview", "rust-analyzer-preview"];
 
-#[derive(Serialize)]
-#[serde(rename_all = "kebab-case")]
-struct Manifest {
-    manifest_version: String,
-    date: String,
-    pkg: BTreeMap<String, Package>,
-    renames: BTreeMap<String, Rename>,
-    profiles: BTreeMap<String, Vec<String>>,
-}
-
-#[derive(Serialize)]
-struct Package {
-    version: String,
-    git_commit_hash: Option<String>,
-    target: BTreeMap<String, Target>,
-}
-
-#[derive(Serialize)]
-struct Rename {
-    to: String,
-}
-
-#[derive(Serialize, Default)]
-struct Target {
-    available: bool,
-    url: Option<String>,
-    hash: Option<String>,
-    xz_url: Option<String>,
-    xz_hash: Option<String>,
-    components: Option<Vec<Component>>,
-    extensions: Option<Vec<Component>>,
-}
-
-impl Target {
-    fn unavailable() -> Self {
-        Self::default()
-    }
-}
-
-#[derive(Serialize)]
-struct Component {
-    pkg: String,
-    target: String,
-}
-
-impl Component {
-    fn from_str(pkg: &str, target: &str) -> Self {
-        Self { pkg: pkg.to_string(), target: target.to_string() }
-    }
-}
-
 macro_rules! t {
     ($e:expr) => {
         match $e {
@@ -226,175 +185,89 @@
 }
 
 struct Builder {
-    rust_release: String,
-    cargo_release: String,
-    rls_release: String,
-    rust_analyzer_release: String,
-    clippy_release: String,
-    rustfmt_release: String,
-    llvm_tools_release: String,
-    miri_release: String,
+    versions: Versions,
 
     input: PathBuf,
     output: PathBuf,
-    gpg_passphrase: String,
-    digests: BTreeMap<String, String>,
     s3_address: String,
     date: String,
 
-    rust_version: Option<String>,
-    cargo_version: Option<String>,
-    rls_version: Option<String>,
-    rust_analyzer_version: Option<String>,
-    clippy_version: Option<String>,
-    rustfmt_version: Option<String>,
-    llvm_tools_version: Option<String>,
-    miri_version: Option<String>,
-
-    rust_git_commit_hash: Option<String>,
-    cargo_git_commit_hash: Option<String>,
-    rls_git_commit_hash: Option<String>,
-    rust_analyzer_git_commit_hash: Option<String>,
-    clippy_git_commit_hash: Option<String>,
-    rustfmt_git_commit_hash: Option<String>,
-    llvm_tools_git_commit_hash: Option<String>,
-    miri_git_commit_hash: Option<String>,
-
-    should_sign: bool,
+    legacy: bool,
+    legacy_gpg_passphrase: String,
 }
 
 fn main() {
-    // Avoid signing packages while manually testing
-    // Do NOT set this envvar in CI
-    let should_sign = env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err();
+    // Up until Rust 1.48 the release process relied on build-manifest to create the SHA256
+    // checksums of released files and to sign the tarballs. That was moved over to promote-release
+    // in time for the branching of Rust 1.48, but the old release process still had to work the
+    // old way.
+    //
+    // When running build-manifest through the old ./x.py dist hash-and-sign the environment
+    // variable will be set, enabling the legacy behavior of generating the .sha256 files and
+    // signing the tarballs.
+    //
+    // Once the old release process is fully decommissioned, the environment variable, all the
+    // related code in this tool and ./x.py dist hash-and-sign can be removed.
+    let legacy = env::var_os("BUILD_MANIFEST_LEGACY").is_some();
 
-    // Safety check to ensure signing is always enabled on CI
-    // The CI environment variable is set by both Travis and AppVeyor
-    if !should_sign && env::var("CI").is_ok() {
-        println!("The 'BUILD_MANIFEST_DISABLE_SIGNING' env var can't be enabled on CI.");
-        println!("If you're not running this on CI, unset the 'CI' env var.");
-        panic!();
-    }
+    let num_threads = if legacy {
+        // Avoid overloading the old server in legacy mode.
+        1
+    } else 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 {
+        num_cpus::get()
+    };
+    rayon::ThreadPoolBuilder::new()
+        .num_threads(num_threads)
+        .build_global()
+        .expect("failed to initialize Rayon");
 
     let mut args = env::args().skip(1);
     let input = PathBuf::from(args.next().unwrap());
     let output = PathBuf::from(args.next().unwrap());
     let date = args.next().unwrap();
-    let rust_release = args.next().unwrap();
     let s3_address = args.next().unwrap();
-    let cargo_release = args.next().unwrap();
-    let rls_release = args.next().unwrap();
-    let rust_analyzer_release = args.next().unwrap();
-    let clippy_release = args.next().unwrap();
-    let miri_release = args.next().unwrap();
-    let rustfmt_release = args.next().unwrap();
-    let llvm_tools_release = args.next().unwrap();
+    let channel = args.next().unwrap();
 
     // Do not ask for a passphrase while manually testing
     let mut passphrase = String::new();
-    if should_sign {
+    if legacy {
         // `x.py` passes the passphrase via stdin.
         t!(io::stdin().read_to_string(&mut passphrase));
     }
 
     Builder {
-        rust_release,
-        cargo_release,
-        rls_release,
-        rust_analyzer_release,
-        clippy_release,
-        rustfmt_release,
-        llvm_tools_release,
-        miri_release,
+        versions: Versions::new(&channel, &input).unwrap(),
 
         input,
         output,
-        gpg_passphrase: passphrase,
-        digests: BTreeMap::new(),
         s3_address,
         date,
 
-        rust_version: None,
-        cargo_version: None,
-        rls_version: None,
-        rust_analyzer_version: None,
-        clippy_version: None,
-        rustfmt_version: None,
-        llvm_tools_version: None,
-        miri_version: None,
-
-        rust_git_commit_hash: None,
-        cargo_git_commit_hash: None,
-        rls_git_commit_hash: None,
-        rust_analyzer_git_commit_hash: None,
-        clippy_git_commit_hash: None,
-        rustfmt_git_commit_hash: None,
-        llvm_tools_git_commit_hash: None,
-        miri_git_commit_hash: None,
-
-        should_sign,
+        legacy,
+        legacy_gpg_passphrase: passphrase,
     }
     .build();
 }
 
-enum PkgType {
-    RustSrc,
-    Cargo,
-    Rls,
-    RustAnalyzer,
-    Clippy,
-    Rustfmt,
-    LlvmTools,
-    Miri,
-    Other,
-}
-
-impl PkgType {
-    fn from_component(component: &str) -> Self {
-        use PkgType::*;
-        match component {
-            "rust-src" => RustSrc,
-            "cargo" => Cargo,
-            "rls" | "rls-preview" => Rls,
-            "rust-analyzer" | "rust-analyzer-preview" => RustAnalyzer,
-            "clippy" | "clippy-preview" => Clippy,
-            "rustfmt" | "rustfmt-preview" => Rustfmt,
-            "llvm-tools" | "llvm-tools-preview" => LlvmTools,
-            "miri" | "miri-preview" => Miri,
-            _ => Other,
-        }
-    }
-}
-
 impl Builder {
     fn build(&mut self) {
-        self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu");
-        self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu");
-        self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu");
-        self.rust_analyzer_version = self.version("rust-analyzer", "x86_64-unknown-linux-gnu");
-        self.clippy_version = self.version("clippy", "x86_64-unknown-linux-gnu");
-        self.rustfmt_version = self.version("rustfmt", "x86_64-unknown-linux-gnu");
-        self.llvm_tools_version = self.version("llvm-tools", "x86_64-unknown-linux-gnu");
-        self.miri_version = self.version("miri", "x86_64-unknown-linux-gnu");
-
-        self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu");
-        self.cargo_git_commit_hash = self.git_commit_hash("cargo", "x86_64-unknown-linux-gnu");
-        self.rls_git_commit_hash = self.git_commit_hash("rls", "x86_64-unknown-linux-gnu");
-        self.rust_analyzer_git_commit_hash =
-            self.git_commit_hash("rust-analyzer", "x86_64-unknown-linux-gnu");
-        self.clippy_git_commit_hash = self.git_commit_hash("clippy", "x86_64-unknown-linux-gnu");
-        self.rustfmt_git_commit_hash = self.git_commit_hash("rustfmt", "x86_64-unknown-linux-gnu");
-        self.llvm_tools_git_commit_hash =
-            self.git_commit_hash("llvm-tools", "x86_64-unknown-linux-gnu");
-        self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu");
-
         self.check_toolstate();
-        self.digest_and_sign();
+        if self.legacy {
+            self.digest_and_sign();
+        }
         let manifest = self.build_manifest();
-        self.write_channel_files(&self.rust_release, &manifest);
 
-        if self.rust_release != "beta" && self.rust_release != "nightly" {
-            self.write_channel_files("stable", &manifest);
+        self.write_channel_files(self.versions.channel(), &manifest);
+        if self.versions.channel() == "stable" {
+            // channel-rust-1.XX.YY.toml
+            let rust_version = self.versions.rustc_version();
+            self.write_channel_files(rust_version, &manifest);
+
+            // channel-rust-1.XX.toml
+            let major_minor = rust_version.split('.').take(2).collect::<Vec<_>>().join(".");
+            self.write_channel_files(&major_minor, &manifest);
         }
     }
 
@@ -415,18 +288,16 @@
         // Mark some tools as missing based on toolstate.
         if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") {
             println!("Miri tests are not passing, removing component");
-            self.miri_version = None;
-            self.miri_git_commit_hash = None;
+            self.versions.disable_version(&PkgType::Miri);
         }
     }
 
     /// Hash all files, compute their signatures, and collect the hashes in `self.digests`.
     fn digest_and_sign(&mut self) {
         for file in t!(self.input.read_dir()).map(|e| t!(e).path()) {
-            let filename = file.file_name().unwrap().to_str().unwrap();
-            let digest = self.hash(&file);
+            file.file_name().unwrap().to_str().unwrap();
+            self.hash(&file);
             self.sign(&file);
-            assert!(self.digests.insert(filename.to_string(), digest).is_none());
         }
     }
 
@@ -442,6 +313,9 @@
         self.add_profiles_to(&mut manifest);
         self.add_renames_to(&mut manifest);
         manifest.pkg.insert("rust".to_string(), self.rust_package(&manifest));
+
+        self.fill_missing_hashes(&mut manifest);
+
         manifest
     }
 
@@ -501,7 +375,7 @@
         // The compiler libraries are not stable for end users, and they're also huge, so we only
         // `rustc-dev` for nightly users, and only in the "complete" profile. It's still possible
         // for users to install the additional component manually, if needed.
-        if self.rust_release == "nightly" {
+        if self.versions.channel() == "nightly" {
             self.extend_profile("complete", &mut manifest.profiles, &["rustc-dev"]);
             self.extend_profile("complete", &mut manifest.profiles, &["rustc-docs"]);
         }
@@ -518,13 +392,10 @@
     }
 
     fn rust_package(&mut self, manifest: &Manifest) -> Package {
+        let version_info = self.versions.version(&PkgType::Rust).expect("missing Rust tarball");
         let mut pkg = Package {
-            version: self
-                .cached_version("rust")
-                .as_ref()
-                .expect("Couldn't find Rust version")
-                .clone(),
-            git_commit_hash: self.cached_git_commit_hash("rust").clone(),
+            version: version_info.version.expect("missing Rust version"),
+            git_commit_hash: version_info.git_commit,
             target: BTreeMap::new(),
         };
         for host in HOSTS {
@@ -539,10 +410,13 @@
     }
 
     fn target_host_combination(&mut self, host: &str, manifest: &Manifest) -> Option<Target> {
-        let filename = self.filename("rust", host);
-        let digest = self.digests.remove(&filename)?;
-        let xz_filename = filename.replace(".tar.gz", ".tar.xz");
-        let xz_digest = self.digests.remove(&xz_filename);
+        let filename = self.versions.tarball_name(&PkgType::Rust, host).unwrap();
+
+        let mut target = Target::from_compressed_tar(self, &filename);
+        if !target.available {
+            return None;
+        }
+
         let mut components = Vec::new();
         let mut extensions = Vec::new();
 
@@ -598,15 +472,9 @@
         extensions.retain(&has_component);
         components.retain(&has_component);
 
-        Some(Target {
-            available: true,
-            url: Some(self.url(&filename)),
-            hash: Some(digest),
-            xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)),
-            xz_hash: xz_digest,
-            components: Some(components),
-            extensions: Some(extensions),
-        })
+        target.components = Some(components);
+        target.extensions = Some(extensions);
+        Some(target)
     }
 
     fn profile(
@@ -630,135 +498,49 @@
     }
 
     fn package(&mut self, pkgname: &str, dst: &mut BTreeMap<String, Package>, targets: &[&str]) {
-        let (version, mut is_present) = self
-            .cached_version(pkgname)
-            .as_ref()
-            .cloned()
-            .map(|version| (version, true))
-            .unwrap_or_default(); // `is_present` defaults to `false` here.
+        let version_info = self
+            .versions
+            .version(&PkgType::from_component(pkgname))
+            .expect("failed to load package version");
+        let mut is_present = version_info.present;
 
         // Never ship nightly-only components for other trains.
-        if self.rust_release != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) {
+        if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) {
             is_present = false; // Pretend the component is entirely missing.
         }
 
         let targets = targets
             .iter()
             .map(|name| {
-                if is_present {
-                    // The component generally exists, but it might still be missing for this target.
-                    let filename = self.filename(pkgname, name);
-                    let digest = match self.digests.remove(&filename) {
-                        Some(digest) => digest,
-                        // This component does not exist for this target -- skip it.
-                        None => return (name.to_string(), Target::unavailable()),
-                    };
-                    let xz_filename = filename.replace(".tar.gz", ".tar.xz");
-                    let xz_digest = self.digests.remove(&xz_filename);
+                let target = if is_present {
+                    let filename = self
+                        .versions
+                        .tarball_name(&PkgType::from_component(pkgname), name)
+                        .unwrap();
 
-                    (
-                        name.to_string(),
-                        Target {
-                            available: true,
-                            url: Some(self.url(&filename)),
-                            hash: Some(digest),
-                            xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)),
-                            xz_hash: xz_digest,
-                            components: None,
-                            extensions: None,
-                        },
-                    )
+                    Target::from_compressed_tar(self, &filename)
                 } else {
                     // If the component is not present for this build add it anyway but mark it as
                     // unavailable -- this way rustup won't allow upgrades without --force
-                    (name.to_string(), Target::unavailable())
-                }
+                    Target::unavailable()
+                };
+                (name.to_string(), target)
             })
             .collect();
 
         dst.insert(
             pkgname.to_string(),
             Package {
-                version,
-                git_commit_hash: self.cached_git_commit_hash(pkgname).clone(),
+                version: version_info.version.unwrap_or_default(),
+                git_commit_hash: version_info.git_commit,
                 target: targets,
             },
         );
     }
 
-    fn url(&self, filename: &str) -> String {
-        format!("{}/{}/{}", self.s3_address, self.date, filename)
-    }
-
-    fn filename(&self, component: &str, target: &str) -> String {
-        use PkgType::*;
-        match PkgType::from_component(component) {
-            RustSrc => format!("rust-src-{}.tar.gz", self.rust_release),
-            Cargo => format!("cargo-{}-{}.tar.gz", self.cargo_release, target),
-            Rls => format!("rls-{}-{}.tar.gz", self.rls_release, target),
-            RustAnalyzer => {
-                format!("rust-analyzer-{}-{}.tar.gz", self.rust_analyzer_release, target)
-            }
-            Clippy => format!("clippy-{}-{}.tar.gz", self.clippy_release, target),
-            Rustfmt => format!("rustfmt-{}-{}.tar.gz", self.rustfmt_release, target),
-            LlvmTools => format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target),
-            Miri => format!("miri-{}-{}.tar.gz", self.miri_release, target),
-            Other => format!("{}-{}-{}.tar.gz", component, self.rust_release, target),
-        }
-    }
-
-    fn cached_version(&self, component: &str) -> &Option<String> {
-        use PkgType::*;
-        match PkgType::from_component(component) {
-            Cargo => &self.cargo_version,
-            Rls => &self.rls_version,
-            RustAnalyzer => &self.rust_analyzer_version,
-            Clippy => &self.clippy_version,
-            Rustfmt => &self.rustfmt_version,
-            LlvmTools => &self.llvm_tools_version,
-            Miri => &self.miri_version,
-            _ => &self.rust_version,
-        }
-    }
-
-    fn cached_git_commit_hash(&self, component: &str) -> &Option<String> {
-        use PkgType::*;
-        match PkgType::from_component(component) {
-            Cargo => &self.cargo_git_commit_hash,
-            Rls => &self.rls_git_commit_hash,
-            RustAnalyzer => &self.rust_analyzer_git_commit_hash,
-            Clippy => &self.clippy_git_commit_hash,
-            Rustfmt => &self.rustfmt_git_commit_hash,
-            LlvmTools => &self.llvm_tools_git_commit_hash,
-            Miri => &self.miri_git_commit_hash,
-            _ => &self.rust_git_commit_hash,
-        }
-    }
-
-    fn version(&self, component: &str, target: &str) -> Option<String> {
-        self.untar(component, target, |filename| format!("{}/version", filename))
-    }
-
-    fn git_commit_hash(&self, component: &str, target: &str) -> Option<String> {
-        self.untar(component, target, |filename| format!("{}/git-commit-hash", filename))
-    }
-
-    fn untar<F>(&self, component: &str, target: &str, dir: F) -> Option<String>
-    where
-        F: FnOnce(String) -> String,
-    {
-        let mut cmd = Command::new("tar");
-        let filename = self.filename(component, target);
-        cmd.arg("xf")
-            .arg(self.input.join(&filename))
-            .arg(dir(filename.replace(".tar.gz", "")))
-            .arg("-O");
-        let output = t!(cmd.output());
-        if output.status.success() {
-            Some(String::from_utf8_lossy(&output.stdout).trim().to_string())
-        } else {
-            None
-        }
+    fn url(&self, path: &Path) -> String {
+        let file_name = path.file_name().unwrap().to_str().unwrap();
+        format!("{}/{}/{}", self.s3_address, self.date, file_name)
     }
 
     fn hash(&self, path: &Path) -> String {
@@ -779,7 +561,7 @@
     }
 
     fn sign(&self, path: &Path) {
-        if !self.should_sign {
+        if !self.legacy {
             return;
         }
 
@@ -802,10 +584,45 @@
             .arg(path)
             .stdin(Stdio::piped());
         let mut child = t!(cmd.spawn());
-        t!(child.stdin.take().unwrap().write_all(self.gpg_passphrase.as_bytes()));
+        t!(child.stdin.take().unwrap().write_all(self.legacy_gpg_passphrase.as_bytes()));
         assert!(t!(child.wait()).success());
     }
 
+    fn fill_missing_hashes(&self, manifest: &mut Manifest) {
+        // First collect all files that need hashes
+        let mut need_hashes = HashSet::new();
+        crate::manifest::visit_file_hashes(manifest, |file_hash| {
+            if let FileHash::Missing(path) = file_hash {
+                need_hashes.insert(path.clone());
+            }
+        });
+
+        let collected = Mutex::new(HashMap::new());
+        let collection_start = Instant::now();
+        println!(
+            "collecting hashes for {} tarballs across {} threads",
+            need_hashes.len(),
+            rayon::current_num_threads().min(need_hashes.len()),
+        );
+        need_hashes.par_iter().for_each(|path| match fetch_hash(path) {
+            Ok(hash) => {
+                collected.lock().unwrap().insert(path, hash);
+            }
+            Err(err) => eprintln!("error while fetching the hash for {}: {}", path.display(), err),
+        });
+        let collected = collected.into_inner().unwrap();
+        println!("collected {} hashes in {:.2?}", collected.len(), collection_start.elapsed());
+
+        crate::manifest::visit_file_hashes(manifest, |file_hash| {
+            if let FileHash::Missing(path) = file_hash {
+                match collected.get(path) {
+                    Some(hash) => *file_hash = FileHash::Present(hash.clone()),
+                    None => panic!("missing hash for file {}", path.display()),
+                }
+            }
+        })
+    }
+
     fn write_channel_files(&self, channel_name: &str, manifest: &Manifest) {
         self.write(&toml::to_string(&manifest).unwrap(), channel_name, ".toml");
         self.write(&manifest.date, channel_name, "-date.txt");
@@ -819,7 +636,16 @@
     fn write(&self, contents: &str, channel_name: &str, suffix: &str) {
         let dst = self.output.join(format!("channel-rust-{}{}", channel_name, suffix));
         t!(fs::write(&dst, contents));
-        self.hash(&dst);
-        self.sign(&dst);
+        if self.legacy {
+            self.hash(&dst);
+            self.sign(&dst);
+        }
     }
 }
+
+fn fetch_hash(path: &Path) -> Result<String, Box<dyn Error>> {
+    let mut file = BufReader::new(File::open(path)?);
+    let mut sha256 = sha2::Sha256::default();
+    std::io::copy(&mut file, &mut sha256)?;
+    Ok(hex::encode(sha256.finalize()))
+}
diff --git a/src/tools/build-manifest/src/manifest.rs b/src/tools/build-manifest/src/manifest.rs
new file mode 100644
index 0000000..20e62ab
--- /dev/null
+++ b/src/tools/build-manifest/src/manifest.rs
@@ -0,0 +1,114 @@
+use crate::Builder;
+use serde::{Serialize, Serializer};
+use std::collections::BTreeMap;
+use std::path::{Path, PathBuf};
+
+#[derive(Serialize)]
+#[serde(rename_all = "kebab-case")]
+pub(crate) struct Manifest {
+    pub(crate) manifest_version: String,
+    pub(crate) date: String,
+    pub(crate) pkg: BTreeMap<String, Package>,
+    pub(crate) renames: BTreeMap<String, Rename>,
+    pub(crate) profiles: BTreeMap<String, Vec<String>>,
+}
+
+#[derive(Serialize)]
+pub(crate) struct Package {
+    pub(crate) version: String,
+    pub(crate) git_commit_hash: Option<String>,
+    pub(crate) target: BTreeMap<String, Target>,
+}
+
+#[derive(Serialize)]
+pub(crate) struct Rename {
+    pub(crate) to: String,
+}
+
+#[derive(Serialize, Default)]
+pub(crate) struct Target {
+    pub(crate) available: bool,
+    pub(crate) url: Option<String>,
+    pub(crate) hash: Option<FileHash>,
+    pub(crate) xz_url: Option<String>,
+    pub(crate) xz_hash: Option<FileHash>,
+    pub(crate) components: Option<Vec<Component>>,
+    pub(crate) extensions: Option<Vec<Component>>,
+}
+
+impl Target {
+    pub(crate) fn from_compressed_tar(builder: &Builder, base_path: &str) -> Self {
+        let base_path = builder.input.join(base_path);
+        let gz = Self::tarball_variant(&base_path, "gz");
+        let xz = Self::tarball_variant(&base_path, "xz");
+
+        if gz.is_none() {
+            return Self::unavailable();
+        }
+
+        Self {
+            available: true,
+            components: None,
+            extensions: None,
+            // .gz
+            url: gz.as_ref().map(|path| builder.url(path)),
+            hash: gz.map(FileHash::Missing),
+            // .xz
+            xz_url: xz.as_ref().map(|path| builder.url(path)),
+            xz_hash: xz.map(FileHash::Missing),
+        }
+    }
+
+    fn tarball_variant(base: &Path, ext: &str) -> Option<PathBuf> {
+        let mut path = base.to_path_buf();
+        path.set_extension(ext);
+        if path.is_file() { Some(path) } else { None }
+    }
+
+    pub(crate) fn unavailable() -> Self {
+        Self::default()
+    }
+}
+
+#[derive(Serialize)]
+pub(crate) struct Component {
+    pub(crate) pkg: String,
+    pub(crate) target: String,
+}
+
+impl Component {
+    pub(crate) fn from_str(pkg: &str, target: &str) -> Self {
+        Self { pkg: pkg.to_string(), target: target.to_string() }
+    }
+}
+
+#[allow(unused)]
+pub(crate) enum FileHash {
+    Missing(PathBuf),
+    Present(String),
+}
+
+impl Serialize for FileHash {
+    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        match self {
+            FileHash::Missing(path) => Err(serde::ser::Error::custom(format!(
+                "can't serialize a missing hash for file {}",
+                path.display()
+            ))),
+            FileHash::Present(inner) => inner.serialize(serializer),
+        }
+    }
+}
+
+pub(crate) fn visit_file_hashes(manifest: &mut Manifest, mut f: impl FnMut(&mut FileHash)) {
+    for pkg in manifest.pkg.values_mut() {
+        for target in pkg.target.values_mut() {
+            if let Some(hash) = &mut target.hash {
+                f(hash);
+            }
+            if let Some(hash) = &mut target.xz_hash {
+                f(hash);
+            }
+        }
+    }
+}
diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs
new file mode 100644
index 0000000..79f2ef8
--- /dev/null
+++ b/src/tools/build-manifest/src/versions.rs
@@ -0,0 +1,191 @@
+use anyhow::Error;
+use flate2::read::GzDecoder;
+use std::collections::HashMap;
+use std::fs::File;
+use std::io::Read;
+use std::path::{Path, PathBuf};
+use tar::Archive;
+
+const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";
+const RUSTC_VERSION: &str = include_str!("../../../version");
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone)]
+pub(crate) enum PkgType {
+    Rust,
+    RustSrc,
+    Cargo,
+    Rls,
+    RustAnalyzer,
+    Clippy,
+    Rustfmt,
+    LlvmTools,
+    Miri,
+    Other(String),
+}
+
+impl PkgType {
+    pub(crate) fn from_component(component: &str) -> Self {
+        match component {
+            "rust" => PkgType::Rust,
+            "rust-src" => PkgType::RustSrc,
+            "cargo" => PkgType::Cargo,
+            "rls" | "rls-preview" => PkgType::Rls,
+            "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer,
+            "clippy" | "clippy-preview" => PkgType::Clippy,
+            "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt,
+            "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools,
+            "miri" | "miri-preview" => PkgType::Miri,
+            other => PkgType::Other(other.into()),
+        }
+    }
+
+    /// First part of the tarball name.
+    fn tarball_component_name(&self) -> &str {
+        match self {
+            PkgType::Rust => "rust",
+            PkgType::RustSrc => "rust-src",
+            PkgType::Cargo => "cargo",
+            PkgType::Rls => "rls",
+            PkgType::RustAnalyzer => "rust-analyzer",
+            PkgType::Clippy => "clippy",
+            PkgType::Rustfmt => "rustfmt",
+            PkgType::LlvmTools => "llvm-tools",
+            PkgType::Miri => "miri",
+            PkgType::Other(component) => component,
+        }
+    }
+
+    /// Whether this package has the same version as Rust itself, or has its own `version` and
+    /// `git-commit-hash` files inside the tarball.
+    fn should_use_rust_version(&self) -> bool {
+        match self {
+            PkgType::Cargo => false,
+            PkgType::Rls => false,
+            PkgType::RustAnalyzer => false,
+            PkgType::Clippy => false,
+            PkgType::Rustfmt => false,
+            PkgType::LlvmTools => false,
+            PkgType::Miri => false,
+
+            PkgType::Rust => true,
+            PkgType::RustSrc => true,
+            PkgType::Other(_) => true,
+        }
+    }
+
+    /// Whether this package is target-independent or not.
+    fn target_independent(&self) -> bool {
+        *self == PkgType::RustSrc
+    }
+}
+
+#[derive(Debug, Default, Clone)]
+pub(crate) struct VersionInfo {
+    pub(crate) version: Option<String>,
+    pub(crate) git_commit: Option<String>,
+    pub(crate) present: bool,
+}
+
+pub(crate) struct Versions {
+    channel: String,
+    dist_path: PathBuf,
+    versions: HashMap<PkgType, VersionInfo>,
+}
+
+impl Versions {
+    pub(crate) fn new(channel: &str, dist_path: &Path) -> Result<Self, Error> {
+        Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() })
+    }
+
+    pub(crate) fn channel(&self) -> &str {
+        &self.channel
+    }
+
+    pub(crate) fn version(&mut self, mut package: &PkgType) -> Result<VersionInfo, Error> {
+        if package.should_use_rust_version() {
+            package = &PkgType::Rust;
+        }
+
+        match self.versions.get(package) {
+            Some(version) => Ok(version.clone()),
+            None => {
+                let version_info = self.load_version_from_tarball(package)?;
+                self.versions.insert(package.clone(), version_info.clone());
+                Ok(version_info)
+            }
+        }
+    }
+
+    fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> {
+        let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?;
+        let tarball = self.dist_path.join(tarball_name);
+
+        let file = match File::open(&tarball) {
+            Ok(file) => file,
+            Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
+                // Missing tarballs do not return an error, but return empty data.
+                return Ok(VersionInfo::default());
+            }
+            Err(err) => return Err(err.into()),
+        };
+        let mut tar = Archive::new(GzDecoder::new(file));
+
+        let mut version = None;
+        let mut git_commit = None;
+        for entry in tar.entries()? {
+            let mut entry = entry?;
+
+            let dest;
+            match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) {
+                Some("version") => dest = &mut version,
+                Some("git-commit-hash") => dest = &mut git_commit,
+                _ => continue,
+            }
+            let mut buf = String::new();
+            entry.read_to_string(&mut buf)?;
+            *dest = Some(buf);
+
+            // Short circuit to avoid reading the whole tar file if not necessary.
+            if version.is_some() && git_commit.is_some() {
+                break;
+            }
+        }
+
+        Ok(VersionInfo { version, git_commit, present: true })
+    }
+
+    pub(crate) fn disable_version(&mut self, package: &PkgType) {
+        match self.versions.get_mut(package) {
+            Some(version) => {
+                *version = VersionInfo::default();
+            }
+            None => {
+                self.versions.insert(package.clone(), VersionInfo::default());
+            }
+        }
+    }
+
+    pub(crate) fn tarball_name(
+        &mut self,
+        package: &PkgType,
+        target: &str,
+    ) -> Result<String, Error> {
+        let component_name = package.tarball_component_name();
+        let version = match self.channel.as_str() {
+            "stable" => RUSTC_VERSION.into(),
+            "beta" => "beta".into(),
+            "nightly" => "nightly".into(),
+            _ => format!("{}-dev", RUSTC_VERSION),
+        };
+
+        if package.target_independent() {
+            Ok(format!("{}-{}.tar.gz", component_name, version))
+        } else {
+            Ok(format!("{}-{}-{}.tar.gz", component_name, version, target))
+        }
+    }
+
+    pub(crate) fn rustc_version(&self) -> &str {
+        RUSTC_VERSION
+    }
+}
diff --git a/src/tools/cargo b/src/tools/cargo
index 05c611a..dd83ae5 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 05c611ae3c4255b7a2bcf4fcfa65b20286a07839
+Subproject commit dd83ae55c871d94f060524656abab62ec40b4c40
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index d1dfe36..0bd1332 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,129 @@
 
 ## Unreleased / In Rust Nightly
 
-[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master)
+[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master)
+
+## Rust 1.48
+
+Current beta, release 2020-11-19
+
+[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
+
+### New lints
+
+* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
+* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
+* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
+* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
+* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
+* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
+* [`single_char_push_str`] [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
+
+### Moves and Deprecations
+
+* Downgrade [`verbose_bit_mask`] to pedantic
+  [#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
+
+### Enhancements
+
+* Extend [`precedence`] to handle chains of methods combined with unary negation
+  [#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
+* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
+  [#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
+* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
+  [#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
+* [`invalid_atomic_ordering`]: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
+  [#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
+* Avoid [`redundant_pattern_matching`] triggering in macros
+  [#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
+* [`option_if_let_else`]: distinguish pure from impure `else` expressions
+  [#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
+* [`needless_doctest_main`]: parse doctests instead of using textual search
+  [#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
+* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
+  [#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
+* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
+  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
+* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
+  [#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
+
+### False Positive Fixes
+
+* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
+  [#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
+* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts 
+  [#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
+* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
+  [#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
+* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
+  [#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
+* [`doc_markdown`]: allow using "GraphQL" without backticks
+  [#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
+* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` 
+  [#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
+* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
+  [#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
+* [`should_implement_trait`]: ignore methods with lifetime parameters
+  [#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
+* [`needless_return`]: avoid linting if a temporary borrows a local variable
+  [#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
+* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
+  [#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
+* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
+  [#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
+* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
+  [#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
+
+### Suggestion Fixes/Improvements
+
+* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
+  [#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
+* [`useless_conversion`]: show the type in the error message
+  [#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
+* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message 
+  [#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
+* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
+  [#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
+* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
+  [#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
+* [`collapsible_if`]: don't use expanded code in the suggestion 
+  [#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
+* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
+  [#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
+* [`unit_arg`]: improve the readability of the suggestion
+  [#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
+* [`stable_sort_primitive`]: print the type that is being sorted in the lint message 
+  [#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
+* Show line count and max lines in [`too_many_lines`] lint message
+  [#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
+* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
+  [#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
+* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
+  [#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
+* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>` 
+  [#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
+* Make lint messages adhere to rustc dev guide conventions
+  [#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
+
+### ICE Fixes
+
+* Fix ICE in [`repeat_once`]
+  [#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
+
+### Documentation Improvements
+
+* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
+  [#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
+* [`unnecessary_mut_passed`]: fix typo
+  [#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
+* Add example of false positive to [`ptr_arg`] docs.
+  [#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
+* [`box_vec`], [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
+  [#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
 
 ## Rust 1.47
 
-Current beta, release 2020-10-08
+Current stable, released 2020-10-08
 
 [c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
 
@@ -112,7 +230,7 @@
 
 ## Rust 1.46
 
-Current stable, released 2020-08-27
+Released 2020-08-27
 
 [7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 
@@ -1559,6 +1677,7 @@
 [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
+[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 [`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
@@ -1634,6 +1753,8 @@
 [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
 [`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
 [`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
+[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
+[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
 [`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
@@ -1644,6 +1765,7 @@
 [`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
 [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
+[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
 [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
 [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
@@ -1919,6 +2041,5 @@
 [`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
 [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
-[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
 [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 <!-- end autogenerated links to lint list -->
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index a2984d7..62a8be0 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
 
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index c861efc..b8a4a20 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -8,8 +8,8 @@
 bytecount = "0.6"
 clap = "2.33"
 itertools = "0.9"
+opener = "0.4"
 regex = "1"
-lazy_static = "1.0"
 shell-escape = "0.1"
 walkdir = "2"
 
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 5baa31d..43cb295 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,42 +1,47 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
+#![feature(once_cell)]
 
 use itertools::Itertools;
-use lazy_static::lazy_static;
 use regex::Regex;
 use std::collections::HashMap;
 use std::ffi::OsStr;
 use std::fs;
+use std::lazy::SyncLazy;
 use std::path::{Path, PathBuf};
 use walkdir::WalkDir;
 
 pub mod fmt;
 pub mod new_lint;
 pub mod ra_setup;
+pub mod serve;
 pub mod stderr_length_check;
 pub mod update_lints;
 
-lazy_static! {
-    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(
+static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
+    Regex::new(
         r#"(?x)
-        declare_clippy_lint!\s*[\{(]
-        (?:\s+///.*)*
-        \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
-        (?P<cat>[a-z_]+)\s*,\s*
-        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
-    "#
+    declare_clippy_lint!\s*[\{(]
+    (?:\s+///.*)*
+    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
+    (?P<cat>[a-z_]+)\s*,\s*
+    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
+"#,
     )
-    .unwrap();
-    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(
+    .unwrap()
+});
+
+static DEC_DEPRECATED_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
+    Regex::new(
         r#"(?x)
-        declare_deprecated_lint!\s*[{(]\s*
-        (?:\s+///.*)*
-        \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
-        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
-    "#
+    declare_deprecated_lint!\s*[{(]\s*
+    (?:\s+///.*)*
+    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
+    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
+"#,
     )
-    .unwrap();
-    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
-}
+    .unwrap()
+});
+static NL_ESCAPE_RE: SyncLazy<Regex> = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap());
 
 pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
 
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 281037a..7a8cbd52 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -1,7 +1,7 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 
 use clap::{App, Arg, SubCommand};
-use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints};
+use clippy_dev::{fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints};
 
 fn main() {
     let matches = App::new("Clippy developer tooling")
@@ -100,6 +100,19 @@
                         .required(true),
                 ),
         )
+        .subcommand(
+            SubCommand::with_name("serve")
+                .about("Launch a local 'ALL the Clippy Lints' website in a browser")
+                .arg(
+                    Arg::with_name("port")
+                        .long("port")
+                        .short("p")
+                        .help("Local port for the http server")
+                        .default_value("8000")
+                        .validator_os(serve::validate_port),
+                )
+                .arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
+        )
         .get_matches();
 
     match matches.subcommand() {
@@ -129,6 +142,11 @@
             stderr_length_check::check();
         },
         ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")),
+        ("serve", Some(matches)) => {
+            let port = matches.value_of("port").unwrap().parse().unwrap();
+            let lint = matches.value_of("lint");
+            serve::run(port, lint);
+        },
         _ => {},
     }
 }
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
new file mode 100644
index 0000000..a46c0e4
--- /dev/null
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -0,0 +1,64 @@
+use std::ffi::{OsStr, OsString};
+use std::path::Path;
+use std::process::Command;
+use std::thread;
+use std::time::{Duration, SystemTime};
+
+pub fn run(port: u16, lint: Option<&str>) -> ! {
+    let mut url = Some(match lint {
+        None => format!("http://localhost:{}", port),
+        Some(lint) => format!("http://localhost:{}/#{}", port, lint),
+    });
+
+    loop {
+        if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
+            Command::new("python3")
+                .arg("util/export.py")
+                .spawn()
+                .unwrap()
+                .wait()
+                .unwrap();
+        }
+        if let Some(url) = url.take() {
+            thread::spawn(move || {
+                Command::new("python3")
+                    .arg("-m")
+                    .arg("http.server")
+                    .arg(port.to_string())
+                    .current_dir("util/gh-pages")
+                    .spawn()
+                    .unwrap();
+                // Give some time for python to start
+                thread::sleep(Duration::from_millis(500));
+                // Launch browser after first export.py has completed and http.server is up
+                let _ = opener::open(url);
+            });
+        }
+        thread::sleep(Duration::from_millis(1000));
+    }
+}
+
+fn mtime(path: impl AsRef<Path>) -> SystemTime {
+    let path = path.as_ref();
+    if path.is_dir() {
+        path.read_dir()
+            .into_iter()
+            .flatten()
+            .flatten()
+            .map(|entry| mtime(&entry.path()))
+            .max()
+            .unwrap_or(SystemTime::UNIX_EPOCH)
+    } else {
+        path.metadata()
+            .and_then(|metadata| metadata.modified())
+            .unwrap_or(SystemTime::UNIX_EPOCH)
+    }
+}
+
+#[allow(clippy::missing_errors_doc)]
+pub fn validate_port(arg: &OsStr) -> Result<(), OsString> {
+    match arg.to_string_lossy().parse::<u16>() {
+        Ok(_port) => Ok(()),
+        Err(err) => Err(OsString::from(err.to_string())),
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 341d9e6..fcf817b 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -20,7 +20,6 @@
 cargo_metadata = "0.11.1"
 if_chain = "1.0.0"
 itertools = "0.9"
-lazy_static = "1.0.2"
 pulldown-cmark = { version = "0.8", default-features = false }
 quine-mc_cluskey = "0.2.2"
 regex-syntax = "0.6"
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
new file mode 100644
index 0000000..ef1f1a1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -0,0 +1,125 @@
+use std::fmt;
+
+use crate::utils::span_lint_and_help;
+use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum AsmStyle {
+    Intel,
+    Att,
+}
+
+impl fmt::Display for AsmStyle {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            AsmStyle::Intel => f.write_str("Intel"),
+            AsmStyle::Att => f.write_str("AT&T"),
+        }
+    }
+}
+
+impl std::ops::Not for AsmStyle {
+    type Output = AsmStyle;
+
+    fn not(self) -> AsmStyle {
+        match self {
+            AsmStyle::Intel => AsmStyle::Att,
+            AsmStyle::Att => AsmStyle::Intel,
+        }
+    }
+}
+
+fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr, check_for: AsmStyle) {
+    if let ExprKind::InlineAsm(ref inline_asm) = expr.kind {
+        let style = if inline_asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
+            AsmStyle::Att
+        } else {
+            AsmStyle::Intel
+        };
+
+        if style == check_for {
+            span_lint_and_help(
+                cx,
+                lint,
+                expr.span,
+                &format!("{} x86 assembly syntax used", style),
+                None,
+                &format!("use {} x86 assembly syntax", !style),
+            );
+        }
+    }
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of Intel x86 assembly syntax.
+    ///
+    /// **Why is this bad?** The lint has been enabled to indicate a preference
+    /// for AT&T x86 assembly syntax.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+    /// # }
+    /// ```
+    /// Use instead:
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+    /// # }
+    /// ```
+    pub INLINE_ASM_X86_INTEL_SYNTAX,
+    restriction,
+    "prefer AT&T x86 assembly syntax"
+}
+
+declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]);
+
+impl EarlyLintPass for InlineAsmX86IntelSyntax {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Intel);
+    }
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of AT&T x86 assembly syntax.
+    ///
+    /// **Why is this bad?** The lint has been enabled to indicate a preference
+    /// for Intel x86 assembly syntax.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+    /// # }
+    /// ```
+    /// Use instead:
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+    /// # }
+    /// ```
+    pub INLINE_ASM_X86_ATT_SYNTAX,
+    restriction,
+    "prefer Intel x86 assembly syntax"
+}
+
+declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]);
+
+impl EarlyLintPass for InlineAsmX86AttSyntax {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Att);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index c8f153e..f6eadbd 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -137,17 +137,17 @@
     /// **Example:**
     /// ```rust
     /// // Good (as inner attribute)
-    /// #![inline(always)]
+    /// #![allow(dead_code)]
     ///
     /// fn this_is_fine() { }
     ///
     /// // Bad
-    /// #[inline(always)]
+    /// #[allow(dead_code)]
     ///
     /// fn not_quite_good_code() { }
     ///
     /// // Good (as outer attribute)
-    /// #[inline(always)]
+    /// #[allow(dead_code)]
     /// fn this_is_fine_too() { }
     /// ```
     pub EMPTY_LINE_AFTER_OUTER_ATTR,
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
index 0000d39..062c9bd 100644
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ b/src/tools/clippy/clippy_lints/src/consts.rs
@@ -155,7 +155,7 @@
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
-        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::from(s.as_slice())),
+        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index c17a0e8..c588436 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -163,3 +163,12 @@
     pub REGEX_MACRO,
     "the regex! macro has been removed from the regex crate in 2018"
 }
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** This lint has been uplifted to rustc and is now called
+    /// `drop_bounds`.
+    pub DROP_BOUNDS,
+    "this lint has been uplifted to rustc and is now called `drop_bounds`"
+}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_method.rs b/src/tools/clippy/clippy_lints/src/disallowed_method.rs
new file mode 100644
index 0000000..581c324
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/disallowed_method.rs
@@ -0,0 +1,73 @@
+use crate::utils::span_lint;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Symbol;
+
+declare_clippy_lint! {
+    /// **What it does:** Lints for specific trait methods defined in clippy.toml
+    ///
+    /// **Why is this bad?** Some methods are undesirable in certain contexts,
+    /// and it would be beneficial to lint for them as needed.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// // example code where clippy issues a warning
+    /// foo.bad_method(); // Foo::bad_method is disallowed in the configuration
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// // example code which does not raise clippy warning
+    /// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed
+    /// ```
+    pub DISALLOWED_METHOD,
+    nursery,
+    "use of a disallowed method call"
+}
+
+#[derive(Clone, Debug)]
+pub struct DisallowedMethod {
+    disallowed: FxHashSet<Vec<Symbol>>,
+}
+
+impl DisallowedMethod {
+    pub fn new(disallowed: &FxHashSet<String>) -> Self {
+        Self {
+            disallowed: disallowed
+                .iter()
+                .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
+                .collect(),
+        }
+    }
+}
+
+impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
+
+impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind {
+            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
+
+            let method_call = cx.get_def_path(def_id);
+            if self.disallowed.contains(&method_call) {
+                let method = method_call
+                    .iter()
+                    .map(|s| s.to_ident_string())
+                    .collect::<Vec<_>>()
+                    .join("::");
+
+                span_lint(
+                    cx,
+                    DISALLOWED_METHOD,
+                    expr.span,
+                    &format!("use of a disallowed method `{}`", method),
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/drop_bounds.rs b/src/tools/clippy/clippy_lints/src/drop_bounds.rs
deleted file mode 100644
index ec3b6af..0000000
--- a/src/tools/clippy/clippy_lints/src/drop_bounds.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use crate::utils::{match_def_path, paths, span_lint};
-use if_chain::if_chain;
-use rustc_hir::{GenericBound, GenericParam, WhereBoundPredicate, WherePredicate};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for generics with `std::ops::Drop` as bounds.
-    ///
-    /// **Why is this bad?** `Drop` bounds do not really accomplish anything.
-    /// A type may have compiler-generated drop glue without implementing the
-    /// `Drop` trait itself. The `Drop` trait also only has one method,
-    /// `Drop::drop`, and that function is by fiat not callable in user code.
-    /// So there is really no use case for using `Drop` in trait bounds.
-    ///
-    /// The most likely use case of a drop bound is to distinguish between types
-    /// that have destructors and types that don't. Combined with specialization,
-    /// a naive coder would write an implementation that assumed a type could be
-    /// trivially dropped, then write a specialization for `T: Drop` that actually
-    /// calls the destructor. Except that doing so is not correct; String, for
-    /// example, doesn't actually implement Drop, but because String contains a
-    /// Vec, assuming it can be trivially dropped will leak memory.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// fn foo<T: Drop>() {}
-    /// ```
-    /// Could be written as:
-    /// ```rust
-    /// fn foo<T>() {}
-    /// ```
-    pub DROP_BOUNDS,
-    correctness,
-    "bounds of the form `T: Drop` are useless"
-}
-
-const DROP_BOUNDS_SUMMARY: &str = "bounds of the form `T: Drop` are useless, \
-                                   use `std::mem::needs_drop` to detect if a type has drop glue";
-
-declare_lint_pass!(DropBounds => [DROP_BOUNDS]);
-
-impl<'tcx> LateLintPass<'tcx> for DropBounds {
-    fn check_generic_param(&mut self, cx: &LateContext<'tcx>, p: &'tcx GenericParam<'_>) {
-        for bound in p.bounds.iter() {
-            lint_bound(cx, bound);
-        }
-    }
-    fn check_where_predicate(&mut self, cx: &LateContext<'tcx>, p: &'tcx WherePredicate<'_>) {
-        if let WherePredicate::BoundPredicate(WhereBoundPredicate { bounds, .. }) = p {
-            for bound in *bounds {
-                lint_bound(cx, bound);
-            }
-        }
-    }
-}
-
-fn lint_bound<'tcx>(cx: &LateContext<'tcx>, bound: &'tcx GenericBound<'_>) {
-    if_chain! {
-        if let GenericBound::Trait(t, _) = bound;
-        if let Some(def_id) = t.trait_ref.path.res.opt_def_id();
-        if match_def_path(cx, def_id, &paths::DROP_TRAIT);
-        then {
-            span_lint(
-                cx,
-                DROP_BOUNDS,
-                t.span,
-                DROP_BOUNDS_SUMMARY
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 82549c1..8b02291 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -6,6 +6,7 @@
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_target::abi::LayoutOf;
+use rustc_target::spec::abi::Abi;
 use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 use crate::utils::span_lint;
@@ -60,12 +61,18 @@
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
-        _: intravisit::FnKind<'tcx>,
+        fn_kind: intravisit::FnKind<'tcx>,
         _: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         _: Span,
         hir_id: HirId,
     ) {
+        if let Some(header) = fn_kind.header() {
+            if header.abi != Abi::Rust {
+                return;
+            }
+        }
+
         // If the method is an impl for a trait, don't warn.
         let parent_id = cx.tcx.hir().get_parent_item(hir_id);
         let parent_node = cx.tcx.hir().find(parent_id);
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 2ab257c..d2a322e 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -3,6 +3,7 @@
 use rustc_hir::{Body, FnDecl, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{Opaque, PredicateAtom::Trait};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
@@ -62,9 +63,10 @@
         }
         let ret_ty = utils::return_ty(cx, hir_id);
         if let Opaque(id, subst) = *ret_ty.kind() {
-            let preds = cx.tcx.predicates_of(id).instantiate(cx.tcx, subst);
+            let preds = cx.tcx.explicit_item_bounds(id);
             let mut is_future = false;
-            for p in preds.predicates {
+            for &(p, _span) in preds {
+                let p = p.subst(cx.tcx, subst);
                 if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
                     if Some(trait_ref.def_id()) == cx.tcx.lang_items().future_trait() {
                         is_future = true;
@@ -90,8 +92,13 @@
                         |db| {
                             cx.tcx.infer_ctxt().enter(|infcx| {
                                 for FulfillmentError { obligation, .. } in send_errors {
-                                    infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
-                                    if let Trait(trait_pred, _) = obligation.predicate.skip_binders() {
+                                    infcx.maybe_note_obligation_cause_for_async_await(
+                                        db,
+                                        &obligation,
+                                    );
+                                    if let Trait(trait_pred, _) =
+                                        obligation.predicate.skip_binders()
+                                    {
                                         db.note(&format!(
                                             "`{}` doesn't implement `{}`",
                                             trait_pred.self_ty(),
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index c3ff34e..93b5d9e 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -7,6 +7,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
 #![feature(in_band_lifetimes)]
+#![feature(once_cell)]
 #![feature(or_patterns)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
@@ -153,6 +154,7 @@
 mod approx_const;
 mod arithmetic;
 mod as_conversions;
+mod asm_syntax;
 mod assertions_on_constants;
 mod assign_ops;
 mod async_yields_async;
@@ -176,10 +178,10 @@
 mod default_trait_access;
 mod dereference;
 mod derive;
+mod disallowed_method;
 mod doc;
 mod double_comparison;
 mod double_parens;
-mod drop_bounds;
 mod drop_forget_ref;
 mod duration_subsec;
 mod else_if_without_else;
@@ -478,6 +480,10 @@
         "clippy::regex_macro",
         "the regex! macro has been removed from the regex crate in 2018",
     );
+    store.register_removed(
+        "clippy::drop_bounds",
+        "this lint has been uplifted to rustc and is now called `drop_bounds`",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
     // begin register lints, do not remove this comment, it’s used in `update_lints`
@@ -486,6 +492,8 @@
         &arithmetic::FLOAT_ARITHMETIC,
         &arithmetic::INTEGER_ARITHMETIC,
         &as_conversions::AS_CONVERSIONS,
+        &asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
+        &asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
         &assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
         &assign_ops::ASSIGN_OP_PATTERN,
         &assign_ops::MISREFACTORED_ASSIGN_OP,
@@ -526,13 +534,13 @@
         &derive::DERIVE_ORD_XOR_PARTIAL_ORD,
         &derive::EXPL_IMPL_CLONE_ON_COPY,
         &derive::UNSAFE_DERIVE_DESERIALIZE,
+        &disallowed_method::DISALLOWED_METHOD,
         &doc::DOC_MARKDOWN,
         &doc::MISSING_ERRORS_DOC,
         &doc::MISSING_SAFETY_DOC,
         &doc::NEEDLESS_DOCTEST_MAIN,
         &double_comparison::DOUBLE_COMPARISONS,
         &double_parens::DOUBLE_PARENS,
-        &drop_bounds::DROP_BOUNDS,
         &drop_forget_ref::DROP_COPY,
         &drop_forget_ref::DROP_REF,
         &drop_forget_ref::FORGET_COPY,
@@ -849,9 +857,9 @@
         &types::UNIT_CMP,
         &types::UNNECESSARY_CAST,
         &types::VEC_BOX,
+        &unicode::INVISIBLE_CHARACTERS,
         &unicode::NON_ASCII_LITERAL,
         &unicode::UNICODE_NOT_NFC,
-        &unicode::ZERO_WIDTH_SPACE,
         &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
         &unnamed_address::FN_ADDRESS_COMPARISONS,
         &unnamed_address::VTABLE_ADDRESS_COMPARISONS,
@@ -959,7 +967,6 @@
     store.register_late_pass(|| box strings::StringLitAsBytes);
     store.register_late_pass(|| box derive::Derive);
     store.register_late_pass(|| box types::CharLitAsU8);
-    store.register_late_pass(|| box drop_bounds::DropBounds);
     store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
     store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
     store.register_late_pass(|| box empty_enum::EmptyEnum);
@@ -1119,11 +1126,18 @@
     store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
     store.register_late_pass(|| box manual_strip::ManualStrip);
     store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
         LintId::of(&arithmetic::INTEGER_ARITHMETIC),
         LintId::of(&as_conversions::AS_CONVERSIONS),
+        LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
+        LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
         LintId::of(&create_dir::CREATE_DIR),
         LintId::of(&dbg_macro::DBG_MACRO),
         LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
@@ -1158,6 +1172,7 @@
         LintId::of(&shadow::SHADOW_REUSE),
         LintId::of(&shadow::SHADOW_SAME),
         LintId::of(&strings::STRING_ADD),
+        LintId::of(&types::RC_BUFFER),
         LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
         LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
         LintId::of(&write::PRINT_STDOUT),
@@ -1282,7 +1297,6 @@
         LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
         LintId::of(&double_comparison::DOUBLE_COMPARISONS),
         LintId::of(&double_parens::DOUBLE_PARENS),
-        LintId::of(&drop_bounds::DROP_BOUNDS),
         LintId::of(&drop_forget_ref::DROP_COPY),
         LintId::of(&drop_forget_ref::DROP_REF),
         LintId::of(&drop_forget_ref::FORGET_COPY),
@@ -1463,7 +1477,6 @@
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
         LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
-        LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
         LintId::of(&swap::ALMOST_SWAPPED),
@@ -1492,14 +1505,13 @@
         LintId::of(&types::CHAR_LIT_AS_U8),
         LintId::of(&types::FN_TO_NUMERIC_CAST),
         LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
-        LintId::of(&types::RC_BUFFER),
         LintId::of(&types::REDUNDANT_ALLOCATION),
         LintId::of(&types::TYPE_COMPLEXITY),
         LintId::of(&types::UNIT_ARG),
         LintId::of(&types::UNIT_CMP),
         LintId::of(&types::UNNECESSARY_CAST),
         LintId::of(&types::VEC_BOX),
-        LintId::of(&unicode::ZERO_WIDTH_SPACE),
+        LintId::of(&unicode::INVISIBLE_CHARACTERS),
         LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
@@ -1592,6 +1604,8 @@
         LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED),
         LintId::of(&neg_multiply::NEG_MULTIPLY),
         LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT),
+        LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
+        LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
         LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
         LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
         LintId::of(&panic_unimplemented::PANIC_PARAMS),
@@ -1604,7 +1618,6 @@
         LintId::of(&returns::LET_AND_RETURN),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-        LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
         LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
         LintId::of(&try_err::TRY_ERR),
@@ -1714,7 +1727,6 @@
         LintId::of(&copies::IF_SAME_THEN_ELSE),
         LintId::of(&derive::DERIVE_HASH_XOR_EQ),
         LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
-        LintId::of(&drop_bounds::DROP_BOUNDS),
         LintId::of(&drop_forget_ref::DROP_COPY),
         LintId::of(&drop_forget_ref::DROP_REF),
         LintId::of(&drop_forget_ref::FORGET_COPY),
@@ -1748,8 +1760,6 @@
         LintId::of(&misc::FLOAT_CMP),
         LintId::of(&misc::MODULO_ONE),
         LintId::of(&mut_key::MUTABLE_KEY_TYPE),
-        LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
-        LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
         LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
         LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
         LintId::of(&ptr::MUT_FROM_REF),
@@ -1767,7 +1777,7 @@
         LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
         LintId::of(&types::CAST_REF_TO_MUT),
         LintId::of(&types::UNIT_CMP),
-        LintId::of(&unicode::ZERO_WIDTH_SPACE),
+        LintId::of(&unicode::INVISIBLE_CHARACTERS),
         LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
@@ -1794,7 +1804,6 @@
         LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
         LintId::of(&types::BOX_VEC),
-        LintId::of(&types::RC_BUFFER),
         LintId::of(&types::REDUNDANT_ALLOCATION),
         LintId::of(&vec::USELESS_VEC),
     ]);
@@ -1808,6 +1817,7 @@
     store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
         LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
         LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
+        LintId::of(&disallowed_method::DISALLOWED_METHOD),
         LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
         LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
         LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
@@ -1819,6 +1829,7 @@
         LintId::of(&needless_borrow::NEEDLESS_BORROW),
         LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
         LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE),
+        LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&transmute::USELESS_TRANSMUTE),
         LintId::of(&use_self::USE_SELF),
     ]);
@@ -1897,6 +1908,7 @@
     ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
     ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
     ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
+    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
 }
 
 // only exists to let the dogfood integration test works.
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 4df6827..d7043e7 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -1,21 +1,22 @@
+use crate::utils::paths;
+use crate::utils::{get_trait_def_id, in_macro, span_lint, trait_ref_of_method};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{
-    walk_fn_decl, walk_generic_param, walk_generics, walk_param_bound, walk_ty, NestedVisitorMap, Visitor,
+    walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
+    NestedVisitorMap, Visitor,
 };
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
-    BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item,
-    ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty,
-    TyKind, WhereClause, WherePredicate,
+    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
+    ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier, TraitFn,
+    TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Symbol};
-
-use crate::utils::{in_macro, last_path_segment, span_lint, trait_ref_of_method};
+use std::iter::FromIterator;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for lifetime annotations which can be removed by
@@ -25,8 +26,11 @@
     /// complicated, while there is nothing out of the ordinary going on. Removing
     /// them leads to more readable code.
     ///
-    /// **Known problems:** Potential false negatives: we bail out if the function
-    /// has a `where` clause where lifetimes are mentioned.
+    /// **Known problems:**
+    /// - We bail out if the function has a `where` clause where lifetimes
+    /// are mentioned due to potenial false positives.
+    /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
+    /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
     ///
     /// **Example:**
     /// ```rust
@@ -108,7 +112,7 @@
 }
 
 /// The lifetime of a &-reference.
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, Clone)]
 enum RefLt {
     Unnamed,
     Static,
@@ -127,7 +131,6 @@
         return;
     }
 
-    let mut bounds_lts = Vec::new();
     let types = generics
         .params
         .iter()
@@ -156,13 +159,12 @@
                         if bound.name != LifetimeName::Static && !bound.is_elided() {
                             return;
                         }
-                        bounds_lts.push(bound);
                     }
                 }
             }
         }
     }
-    if could_use_elision(cx, decl, body, &generics.params, bounds_lts) {
+    if could_use_elision(cx, decl, body, &generics.params) {
         span_lint(
             cx,
             NEEDLESS_LIFETIMES,
@@ -181,7 +183,6 @@
     func: &'tcx FnDecl<'_>,
     body: Option<BodyId>,
     named_generics: &'tcx [GenericParam<'_>],
-    bounds_lts: Vec<&'tcx Lifetime>,
 ) -> bool {
     // There are two scenarios where elision works:
     // * no output references, all input references have different LT
@@ -204,15 +205,31 @@
     if let Return(ref ty) = func.output {
         output_visitor.visit_ty(ty);
     }
+    for lt in named_generics {
+        input_visitor.visit_generic_param(lt)
+    }
 
-    let input_lts = match input_visitor.into_vec() {
-        Some(lts) => lts_from_bounds(lts, bounds_lts.into_iter()),
-        None => return false,
-    };
-    let output_lts = match output_visitor.into_vec() {
-        Some(val) => val,
-        None => return false,
-    };
+    if input_visitor.abort() || output_visitor.abort() {
+        return false;
+    }
+
+    if allowed_lts
+        .intersection(&FxHashSet::from_iter(
+            input_visitor
+                .nested_elision_site_lts
+                .iter()
+                .chain(output_visitor.nested_elision_site_lts.iter())
+                .cloned()
+                .filter(|v| matches!(v, RefLt::Named(_))),
+        ))
+        .next()
+        .is_some()
+    {
+        return false;
+    }
+
+    let input_lts = input_visitor.lts;
+    let output_lts = output_visitor.lts;
 
     if let Some(body_id) = body {
         let mut checker = BodyLifetimeChecker {
@@ -277,27 +294,20 @@
     allowed_lts
 }
 
-fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> {
-    for lt in bounds_lts {
-        if lt.name != LifetimeName::Static {
-            vec.push(RefLt::Named(lt.name.ident().name));
-        }
-    }
-
-    vec
-}
-
 /// Number of unique lifetimes in the given vector.
 #[must_use]
 fn unique_lifetimes(lts: &[RefLt]) -> usize {
     lts.iter().collect::<FxHashSet<_>>().len()
 }
 
+const CLOSURE_TRAIT_BOUNDS: [&[&str]; 3] = [&paths::FN, &paths::FN_MUT, &paths::FN_ONCE];
+
 /// A visitor usable for `rustc_front::visit::walk_ty()`.
 struct RefVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     lts: Vec<RefLt>,
-    abort: bool,
+    nested_elision_site_lts: Vec<RefLt>,
+    unelided_trait_object_lifetime: bool,
 }
 
 impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
@@ -305,7 +315,8 @@
         Self {
             cx,
             lts: Vec::new(),
-            abort: false,
+            nested_elision_site_lts: Vec::new(),
+            unelided_trait_object_lifetime: false,
         }
     }
 
@@ -325,40 +336,16 @@
         }
     }
 
-    fn into_vec(self) -> Option<Vec<RefLt>> {
-        if self.abort {
-            None
-        } else {
-            Some(self.lts)
-        }
+    fn all_lts(&self) -> Vec<RefLt> {
+        self.lts
+            .iter()
+            .chain(self.nested_elision_site_lts.iter())
+            .cloned()
+            .collect::<Vec<_>>()
     }
 
-    fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) {
-        if let Some(ref last_path_segment) = last_path_segment(qpath).args {
-            if !last_path_segment.parenthesized
-                && !last_path_segment
-                    .args
-                    .iter()
-                    .any(|arg| matches!(arg, GenericArg::Lifetime(_)))
-            {
-                let hir_id = ty.hir_id;
-                match self.cx.qpath_res(qpath, hir_id) {
-                    Res::Def(DefKind::TyAlias | DefKind::Struct, def_id) => {
-                        let generics = self.cx.tcx.generics_of(def_id);
-                        for _ in generics.params.as_slice() {
-                            self.record(&None);
-                        }
-                    },
-                    Res::Def(DefKind::Trait, def_id) => {
-                        let trait_def = self.cx.tcx.trait_def(def_id);
-                        for _ in &self.cx.tcx.generics_of(trait_def.def_id).params {
-                            self.record(&None);
-                        }
-                    },
-                    _ => (),
-                }
-            }
-        }
+    fn abort(&self) -> bool {
+        self.unelided_trait_object_lifetime
     }
 }
 
@@ -370,30 +357,37 @@
         self.record(&Some(*lifetime));
     }
 
+    fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) {
+        let trait_ref = &poly_tref.trait_ref;
+        if CLOSURE_TRAIT_BOUNDS
+            .iter()
+            .any(|trait_path| trait_ref.trait_def_id() == get_trait_def_id(self.cx, trait_path))
+        {
+            let mut sub_visitor = RefVisitor::new(self.cx);
+            sub_visitor.visit_trait_ref(trait_ref);
+            self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
+        } else {
+            walk_poly_trait_ref(self, poly_tref, tbm);
+        }
+    }
+
     fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         match ty.kind {
-            TyKind::Rptr(ref lt, _) if lt.is_elided() => {
-                self.record(&None);
-            },
-            TyKind::Path(ref path) => {
-                self.collect_anonymous_lifetimes(path, ty);
-            },
             TyKind::OpaqueDef(item, _) => {
                 let map = self.cx.tcx.hir();
-                if let ItemKind::OpaqueTy(ref exist_ty) = map.expect_item(item.id).kind {
-                    for bound in exist_ty.bounds {
-                        if let GenericBound::Outlives(_) = *bound {
-                            self.record(&None);
-                        }
-                    }
-                } else {
-                    unreachable!()
-                }
+                let item = map.expect_item(item.id);
+                walk_item(self, item);
                 walk_ty(self, ty);
             },
+            TyKind::BareFn(&BareFnTy { decl, .. }) => {
+                let mut sub_visitor = RefVisitor::new(self.cx);
+                sub_visitor.visit_fn_decl(decl);
+                self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
+                return;
+            },
             TyKind::TraitObject(bounds, ref lt) => {
                 if !lt.is_elided() {
-                    self.abort = true;
+                    self.unelided_trait_object_lifetime = true;
                 }
                 for bound in bounds {
                     self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
@@ -430,16 +424,7 @@
                     walk_param_bound(&mut visitor, bound);
                 }
                 // and check that all lifetimes are allowed
-                match visitor.into_vec() {
-                    None => return false,
-                    Some(lts) => {
-                        for lt in lts {
-                            if !allowed_lts.contains(&lt) {
-                                return true;
-                            }
-                        }
-                    },
-                }
+                return visitor.all_lts().iter().any(|it| !allowed_lts.contains(it));
             },
             WherePredicate::EqPredicate(ref pred) => {
                 let mut visitor = RefVisitor::new(cx);
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index a36fdca..c54103b 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -264,13 +264,10 @@
 
         let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent {
             (exponent, &["32", "64"][..], 'f')
+        } else if num_lit.fraction.is_some() {
+            (&mut num_lit.integer, &["32", "64"][..], 'f')
         } else {
-            num_lit
-                .fraction
-                .as_mut()
-                .map_or((&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), |fraction| {
-                    (fraction, &["32", "64"][..], 'f')
-                })
+            (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i')
         };
 
         let mut split = part.rsplit('_');
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 3410341..4fdcaca 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -3,7 +3,7 @@
 use crate::utils::sugg::Sugg;
 use crate::utils::usage::{is_unused, mutated_variables};
 use crate::utils::{
-    get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
+    contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
     is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method,
     match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability,
     snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg,
@@ -742,6 +742,7 @@
         | ExprKind::Closure(_, _, _, _, _)
         | ExprKind::LlvmInlineAsm(_)
         | ExprKind::Path(_)
+        | ExprKind::ConstBlock(_)
         | ExprKind::Lit(_)
         | ExprKind::Err => NeverLoopResult::Otherwise,
     }
@@ -1276,6 +1277,8 @@
 
                 let skip = if starts_at_zero {
                     String::new()
+                } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) {
+                    return;
                 } else {
                     format!(".skip({})", snippet(cx, start.span, ".."))
                 };
@@ -1302,6 +1305,8 @@
 
                     if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
                         String::new()
+                    } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
+                        return;
                     } else {
                         match limits {
                             ast::RangeLimits::Closed => {
@@ -2134,7 +2139,7 @@
     DontWarn,
 }
 
-/// Scan a for loop for variables that are incremented exactly once.
+/// Scan a for loop for variables that are incremented exactly once and not used after that.
 struct IncrementVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,          // context reference
     states: FxHashMap<HirId, VarState>, // incremented variables
@@ -2154,6 +2159,10 @@
         if let Some(def_id) = var_def_id(self.cx, expr) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
                 let state = self.states.entry(def_id).or_insert(VarState::Initial);
+                if *state == VarState::IncrOnce {
+                    *state = VarState::DontWarn;
+                    return;
+                }
 
                 match parent.kind {
                     ExprKind::AssignOp(op, ref lhs, ref rhs) => {
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 065c7c0..b4b4b3d 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -18,9 +18,9 @@
     /// **Known problems:** None.
     ///
     /// **Example:**
-    /// ```rust
+    /// ```rust,ignore
     /// #[macro_use]
-    /// use lazy_static;
+    /// use some_macro;
     /// ```
     pub MACRO_USE_IMPORTS,
     pedantic,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index dadd0f8..c0824ba 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -400,8 +400,8 @@
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.map(_).flatten(_)`,
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call using `_.flat_map(_)`
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.flat_map(_)`
     ///
     /// **Known problems:**
     ///
@@ -424,8 +424,8 @@
     /// **What it does:** Checks for usage of `_.filter(_).map(_)`,
     /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.filter_map(_)`.
     ///
     /// **Known problems:** Often requires a condition + Option/Iterator creation
     /// inside the closure.
@@ -452,8 +452,8 @@
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.filter_map(_).next()`.
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.find_map(_)`.
     ///
     /// **Known problems:** None
     ///
@@ -496,8 +496,8 @@
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.find(_).map(_)`.
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.find_map(_)`.
     ///
     /// **Known problems:** Often requires a condition + Option/Iterator creation
     /// inside the closure.
@@ -1276,8 +1276,8 @@
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.as_deref()`.
     ///
     /// **Known problems:** None.
     ///
@@ -1667,7 +1667,7 @@
             // if return type is impl trait, check the associated types
             if let ty::Opaque(def_id, _) = *ret_ty.kind() {
                 // one of the associated types must be Self
-                for &(predicate, _span) in cx.tcx.predicates_of(def_id).predicates {
+                for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
                         // walk the associated type and check for Self
                         if contains_ty(projection_predicate.ty, self_ty) {
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index e5f7cc5..25245b3 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -1,10 +1,10 @@
+use crate::utils::qualify_min_const_fn::is_min_const_fn;
 use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use crate::utils::qualify_min_const_fn::is_min_const_fn;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 use rustc_typeck::hir_ty_to_ty;
@@ -118,7 +118,7 @@
 
         let mir = cx.tcx.optimized_mir(def_id);
 
-        if let Err((span, err)) = is_min_const_fn(cx.tcx, def_id.to_def_id(), &mir) {
+        if let Err((span, err)) = is_min_const_fn(cx.tcx, &mir) {
             if rustc_mir::const_eval::is_min_const_fn(cx.tcx, def_id.to_def_id()) {
                 cx.tcx.sess.span_err(span, &err);
             }
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 38bdd0f..7687962 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,4 +1,4 @@
-use crate::utils::span_lint_and_sugg;
+use crate::utils::{in_macro, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
@@ -69,11 +69,30 @@
         if let [segment] = &path.segments[..];
         if segment.ident.name == kw::SelfUpper;
         then {
+            // In case we have a named lifetime, we check if the name comes from expansion.
+            // If it does, at this point we know the rest of the parameter was written by the user,
+            // so let them decide what the name of the lifetime should be.
+            // See #6089 for more details.
+            let mut applicability = Applicability::MachineApplicable;
             let self_param = match (binding_mode, mutbl) {
                 (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
-                (Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name),
+                (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
+                    if in_macro(lifetime.ident.span) {
+                        applicability = Applicability::HasPlaceholders;
+                        "&'_ mut self".to_string()
+                    } else {
+                        format!("&{} mut self", &lifetime.ident.name)
+                    }
+                },
                 (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
-                (Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name),
+                (Mode::Ref(Some(lifetime)), Mutability::Not) => {
+                    if in_macro(lifetime.ident.span) {
+                        applicability = Applicability::HasPlaceholders;
+                        "&'_ self".to_string()
+                    } else {
+                        format!("&{} self", &lifetime.ident.name)
+                    }
+                },
                 (Mode::Value, Mutability::Mut) => "mut self".to_string(),
                 (Mode::Value, Mutability::Not) => "self".to_string(),
             };
@@ -85,7 +104,7 @@
                 "the type of the `self` parameter does not need to be arbitrary",
                 "consider to change this parameter to",
                 self_param,
-                Applicability::MachineApplicable,
+                applicability,
             )
         }
     }
@@ -93,7 +112,8 @@
 
 impl EarlyLintPass for NeedlessArbitrarySelfType {
     fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
-        if !p.is_self() {
+        // Bail out if the parameter it's not a receiver or was not written by the user
+        if !p.is_self() || in_macro(p.span) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index bb44eeb..7b662ea 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -1,6 +1,6 @@
 //! Checks for uses of const which the type is not `Freeze` (`Cell`-free).
 //!
-//! This lint is **deny** by default.
+//! This lint is **warn** by default.
 
 use std::ptr;
 
@@ -17,6 +17,8 @@
 use crate::utils::{in_constant, qpath_res, span_lint_and_then};
 use if_chain::if_chain;
 
+// FIXME: this is a correctness problem but there's no suitable
+// warn-by-default category.
 declare_clippy_lint! {
     /// **What it does:** Checks for declaration of `const` items which is interior
     /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
@@ -34,6 +36,15 @@
     /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
     /// and this lint should be suppressed.
     ///
+    /// When an enum has variants with interior mutability, use of its non interior mutable
+    /// variants can generate false positives. See issue
+    /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+    ///
+    /// Types that have underlying or potential interior mutability trigger the lint whether
+    /// the interior mutable field is used or not. See issues
+    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+    /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
+    ///
     /// **Example:**
     /// ```rust
     /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
@@ -49,10 +60,12 @@
     /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
     /// ```
     pub DECLARE_INTERIOR_MUTABLE_CONST,
-    correctness,
+    style,
     "declaring `const` with interior mutability"
 }
 
+// FIXME: this is a correctness problem but there's no suitable
+// warn-by-default category.
 declare_clippy_lint! {
     /// **What it does:** Checks if `const` items which is interior mutable (e.g.,
     /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
@@ -64,7 +77,14 @@
     ///
     /// The `const` value should be stored inside a `static` item.
     ///
-    /// **Known problems:** None
+    /// **Known problems:** When an enum has variants with interior mutability, use of its non
+    /// interior mutable variants can generate false positives. See issue
+    /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+    ///
+    /// Types that have underlying or potential interior mutability trigger the lint whether
+    /// the interior mutable field is used or not. See issues
+    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+    /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
     ///
     /// **Example:**
     /// ```rust
@@ -81,7 +101,7 @@
     /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
     /// ```
     pub BORROW_INTERIOR_MUTABLE_CONST,
-    correctness,
+    style,
     "referencing `const` with interior mutability"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 4d20a81..b4502c6 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -86,7 +86,7 @@
         let mir = cx.tcx.optimized_mir(def_id.to_def_id());
 
         let maybe_storage_live_result = MaybeStorageLive
-            .into_engine(cx.tcx, mir, def_id.to_def_id())
+            .into_engine(cx.tcx, mir)
             .pass_name("redundant_clone")
             .iterate_to_fixpoint()
             .into_results_cursor(mir);
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index dfc1586..95594e3 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -143,7 +143,7 @@
 
 fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
     let mut parser = regex_syntax::ParserBuilder::new()
-        .unicode(utf8)
+        .unicode(true)
         .allow_invalid_utf8(!utf8)
         .build();
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 15b6668..3783bd7 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -69,7 +69,27 @@
     /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
     /// instead. They are shorter but less discoverable than `as_bytes()`.
     ///
-    /// **Known Problems:** None.
+    /// **Known Problems:**
+    /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
+    /// equivalent because they have different types. The former is `&[u8]`
+    /// while the latter is `&[u8; 3]`. That means in general they will have a
+    /// different set of methods and different trait implementations.
+    ///
+    /// ```compile_fail
+    /// fn f(v: Vec<u8>) {}
+    ///
+    /// f("...".as_bytes().to_owned()); // works
+    /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
+    ///
+    /// fn g(r: impl std::io::Read) {}
+    ///
+    /// g("...".as_bytes()); // works
+    /// g(b"..."); // does not work
+    /// ```
+    ///
+    /// The actual equivalent of `"str".as_bytes()` with the same type is not
+    /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
+    /// more readable than a function call.
     ///
     /// **Example:**
     /// ```rust
@@ -80,7 +100,7 @@
     /// let bs = b"a byte string";
     /// ```
     pub STRING_LIT_AS_BYTES,
-    style,
+    nursery,
     "calling `as_bytes` on a string literal instead of using a byte string literal"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
index 1f06d2d..d92eb86 100644
--- a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
@@ -9,10 +9,10 @@
 use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::config::Config as SessionConfig;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 use rustc_target::abi::LayoutOf;
+use rustc_target::spec::Target;
 use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
@@ -60,9 +60,9 @@
 }
 
 impl<'tcx> TriviallyCopyPassByRef {
-    pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
+    pub fn new(limit: Option<u64>, target: &Target) -> Self {
         let limit = limit.unwrap_or_else(|| {
-            let bit_width = u64::from(target.ptr_width);
+            let bit_width = u64::from(target.pointer_width);
             // Cap the calculated bit width at 32-bits to reduce
             // portability problems between 32 and 64-bit targets
             let bit_width = cmp::min(bit_width, 32);
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index a29a199..5e83b6c 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -216,18 +216,19 @@
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for Rc<T> and Arc<T> when T is a mutable buffer type such as String or Vec
+    /// **What it does:** Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
     ///
-    /// **Why is this bad?** Expressions such as Rc<String> have no advantage over Rc<str>, since
-    /// it is larger and involves an extra level of indirection, and doesn't implement Borrow<str>.
+    /// **Why is this bad?** Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
+    /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
     ///
-    /// While mutating a buffer type would still be possible with Rc::get_mut(), it only
-    /// works if there are no additional references yet, which defeats the purpose of
+    /// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
+    /// works if there are no additional references yet, which usually defeats the purpose of
     /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner
-    /// type with an interior mutable container (such as RefCell or Mutex) would normally
+    /// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
     /// be used.
     ///
-    /// **Known problems:** None.
+    /// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
+    /// cases where mutation only happens before there are any additional references.
     ///
     /// **Example:**
     /// ```rust,ignore
@@ -241,7 +242,7 @@
     /// fn foo(interned: Rc<str>) { ... }
     /// ```
     pub RC_BUFFER,
-    perf,
+    restriction,
     "shared ownership of a buffer type"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index d8c57f0..93d59cc 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -8,18 +8,18 @@
 use unicode_normalization::UnicodeNormalization;
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for the Unicode zero-width space in the code.
+    /// **What it does:** Checks for invisible Unicode characters in the code.
     ///
     /// **Why is this bad?** Having an invisible character in the code makes for all
     /// sorts of April fools, but otherwise is very much frowned upon.
     ///
     /// **Known problems:** None.
     ///
-    /// **Example:** You don't see it, but there may be a zero-width space
-    /// somewhere in this text.
-    pub ZERO_WIDTH_SPACE,
+    /// **Example:** You don't see it, but there may be a zero-width space or soft hyphen
+    /// some­where in this text.
+    pub INVISIBLE_CHARACTERS,
     correctness,
-    "using a zero-width space in a string literal, which is confusing"
+    "using an invisible character in a string literal, which is confusing"
 }
 
 declare_clippy_lint! {
@@ -63,7 +63,7 @@
     "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)"
 }
 
-declare_lint_pass!(Unicode => [ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
+declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
 
 impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
@@ -91,14 +91,17 @@
 
 fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
     let string = snippet(cx, span, "");
-    if string.contains('\u{200B}') {
+    if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
         span_lint_and_sugg(
             cx,
-            ZERO_WIDTH_SPACE,
+            INVISIBLE_CHARACTERS,
             span,
-            "zero-width space detected",
+            "invisible character detected",
             "consider replacing the string with",
-            string.replace("\u{200B}", "\\u{200B}"),
+            string
+                .replace("\u{200B}", "\\u{200B}")
+                .replace("\u{ad}", "\\u{AD}")
+                .replace("\u{2060}", "\\u{2060}"),
             Applicability::MachineApplicable,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
index 9b6a907..1307237 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -170,22 +170,12 @@
 }
 
 fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
-    // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162,
-    // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested
-    // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more
-    // than one level of references would add some extra complexity as we would have to compensate
-    // in the closure body.
-
     if_chain! {
         if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
         if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
-        let vec_ty = cx.typeck_results().expr_ty(vec);
-        if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type));
-        let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec<T>
-        if !matches!(&ty.kind(), ty::Ref(..));
-        if utils::is_copy(cx, ty);
+        if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym!(vec_type));
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
@@ -210,40 +200,32 @@
             let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
             let unstable = name == "sort_unstable_by";
 
-            if_chain! {
-                if let ExprKind::Path(QPath::Resolved(_, Path {
-                    segments: [PathSegment { ident: left_name, .. }], ..
-                })) = &left_expr.kind;
-                if left_name == left_ident;
-                then {
-                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }))
-                } else {
-                    if !key_returns_borrow(cx, left_expr) {
-                        return Some(LintTrigger::SortByKey(SortByKeyDetection {
-                            vec_name,
-                            unstable,
-                            closure_arg,
-                            closure_body,
-                            reverse
-                        }))
-                    }
+            if let ExprKind::Path(QPath::Resolved(_, Path {
+                segments: [PathSegment { ident: left_name, .. }], ..
+            })) = &left_expr.kind {
+                if left_name == left_ident {
+                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
                 }
             }
+
+            if !expr_borrows(cx, left_expr) {
+                return Some(LintTrigger::SortByKey(SortByKeyDetection {
+                    vec_name,
+                    unstable,
+                    closure_arg,
+                    closure_body,
+                    reverse
+                }));
+            }
         }
     }
 
     None
 }
 
-fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let Some(def_id) = utils::fn_def_id(cx, expr) {
-        let output = cx.tcx.fn_sig(def_id).output();
-        let ty = output.skip_binder();
-        return matches!(ty.kind(), ty::Ref(..))
-            || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
-    }
-
-    false
+fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
 }
 
 impl LateLintPass<'_> for UnnecessarySortBy {
@@ -256,7 +238,7 @@
                 "use Vec::sort_by_key here instead",
                 "try",
                 format!(
-                    "{}.sort{}_by_key(|&{}| {})",
+                    "{}.sort{}_by_key(|{}| {})",
                     trigger.vec_name,
                     if trigger.unstable { "_unstable" } else { "" },
                     trigger.closure_arg,
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 6eda6d1..8942543 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -506,6 +506,11 @@
                 println!("    if {}.len() == {};", fields_pat, fields.len());
                 println!("    // unimplemented: field checks");
             },
+            ExprKind::ConstBlock(_) => {
+                let value_pat = self.next("value");
+                println!("Const({})", value_pat);
+                self.current = value_pat;
+            },
             // FIXME: compute length (needs type info)
             ExprKind::Repeat(ref value, _) => {
                 let value_pat = self.next("value");
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 9c5a12e..dd2fd0b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -2,10 +2,10 @@
 
 #![deny(clippy::missing_docs_in_private_items)]
 
-use lazy_static::lazy_static;
 use rustc_ast::ast::{LitKind, MetaItemKind, NestedMetaItem};
 use rustc_span::source_map;
 use source_map::Span;
+use std::lazy::SyncLazy;
 use std::path::{Path, PathBuf};
 use std::sync::Mutex;
 use std::{env, fmt, fs, io};
@@ -54,9 +54,8 @@
     }
 }
 
-lazy_static! {
-    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
-}
+/// Vec of errors that might be collected during config toml parsing
+static ERRORS: SyncLazy<Mutex<Vec<Error>>> = SyncLazy::new(|| Mutex::new(Vec::new()));
 
 macro_rules! define_Conf {
     ($(#[$doc:meta] ($config:ident, $config_str:literal: $Ty:ty, $default:expr),)+) => {
@@ -82,6 +81,7 @@
                     use serde::Deserialize;
                     pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> {
                         use super::super::{ERRORS, Error};
+
                         Ok(
                             <$Ty>::deserialize(deserializer).unwrap_or_else(|e| {
                                 ERRORS
@@ -164,6 +164,8 @@
     (max_fn_params_bools, "max_fn_params_bools": u64, 3),
     /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
     (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
+    /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
+    (disallowed_methods, "disallowed_methods": Vec<String>, Vec::<String>::new()),
 }
 
 impl Default for Conf {
diff --git a/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs b/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs
index 6938d99..27e9567 100644
--- a/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs
@@ -23,7 +23,7 @@
 /// This function is named so to stress that it isn't exhaustive and returns FNs.
 fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
     match expr.kind {
-        ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
+        ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
         ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr),
         ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)),
         ExprKind::Struct(_, fields, expr) => {
diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
index c7263f4..c9e639e 100644
--- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
@@ -559,6 +559,9 @@
                 self.hash_name(path.ident.name);
                 self.hash_exprs(args);
             },
+            ExprKind::ConstBlock(ref l_id) => {
+                self.hash_body(l_id.body);
+            },
             ExprKind::Repeat(ref e, ref l_id) => {
                 self.hash_expr(e);
                 self.hash_body(l_id.body);
diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
index 4701a3f..93bd829 100644
--- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
@@ -338,6 +338,11 @@
                 print_expr(cx, base, indent + 1);
             }
         },
+        hir::ExprKind::ConstBlock(ref anon_const) => {
+            println!("{}ConstBlock", ind);
+            println!("{}anon_const:", ind);
+            print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+        },
         hir::ExprKind::Repeat(ref val, ref anon_const) => {
             println!("{}Repeat", ind);
             println!("{}value:", ind);
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 96d9905..790ac4f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -18,9 +18,9 @@
 pub mod numeric_literal;
 pub mod paths;
 pub mod ptr;
+pub mod qualify_min_const_fn;
 pub mod sugg;
 pub mod usage;
-pub mod qualify_min_const_fn;
 
 pub use self::attrs::*;
 pub use self::diagnostics::*;
@@ -47,7 +47,6 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
-use rustc_mir::const_eval;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
@@ -884,19 +883,11 @@
 
 /// Checks if an expression is constructing a tuple-like enum variant or struct
 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool {
-        cx.tcx.fn_sig(def_id).skip_binder().inputs().is_empty()
-    }
-
     if let ExprKind::Call(ref fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
-                // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
-                def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => {
-                    const_eval::is_const_fn(cx.tcx, def_id)
-                },
                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
                 _ => false,
             };
@@ -1285,7 +1276,7 @@
         },
         ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(ref def_id, _) => {
-            for (predicate, _) in cx.tcx.predicates_of(*def_id).predicates {
+            for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateAtom::Trait(trait_predicate, _) = predicate.skip_binders() {
                     if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
                         return true;
diff --git a/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs b/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs
index 5e8800d..52d3c2c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs
@@ -36,8 +36,9 @@
     pub integer: &'a str,
     /// The fraction part of the number.
     pub fraction: Option<&'a str>,
-    /// The character used as exponent separator (b'e' or b'E') and the exponent part.
-    pub exponent: Option<(char, &'a str)>,
+    /// The exponent separator (b'e' or b'E') including preceding underscore if present
+    /// and the exponent part.
+    pub exponent: Option<(&'a str, &'a str)>,
 
     /// The type suffix, including preceding underscore if present.
     pub suffix: Option<&'a str>,
@@ -100,7 +101,7 @@
         self.radix == Radix::Decimal
     }
 
-    pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(char, &str)>) {
+    pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(&str, &str)>) {
         let mut integer = digits;
         let mut fraction = None;
         let mut exponent = None;
@@ -113,12 +114,14 @@
                         fraction = Some(&digits[i + 1..]);
                     },
                     'e' | 'E' => {
-                        if integer.len() > i {
-                            integer = &digits[..i];
+                        let exp_start = if digits[..i].ends_with('_') { i - 1 } else { i };
+
+                        if integer.len() > exp_start {
+                            integer = &digits[..exp_start];
                         } else {
-                            fraction = Some(&digits[integer.len() + 1..i]);
+                            fraction = Some(&digits[integer.len() + 1..exp_start]);
                         };
-                        exponent = Some((c, &digits[i + 1..]));
+                        exponent = Some((&digits[exp_start..=i], &digits[i + 1..]));
                         break;
                     },
                     _ => {},
@@ -153,7 +156,7 @@
         }
 
         if let Some((separator, exponent)) = self.exponent {
-            output.push(separator);
+            output.push_str(separator);
             Self::group_digits(&mut output, exponent, group_size, true, false);
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index 1583afa..5e769c6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -14,7 +14,7 @@
 pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
 pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"];
 pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
-pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"];
+pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"];
 pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];
 pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
 pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
@@ -31,7 +31,6 @@
 pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
 pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
 pub const DROP: [&str; 3] = ["core", "mem", "drop"];
-pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"];
 pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
 pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
 pub const EXIT: [&str; 3] = ["std", "process", "exit"];
@@ -42,6 +41,9 @@
 pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
 pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
 pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
+pub const FN: [&str; 3] = ["core", "ops", "Fn"];
+pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
+pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
 pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
 pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
index 6809b1f..7cb7d0a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
@@ -1,16 +1,20 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::mir::*;
+use rustc_middle::mir::{
+    Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
+    TerminatorKind,
+};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
-use rustc_span::symbol::{sym};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi::RustIntrinsic;
 use std::borrow::Cow;
 
 type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
-pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult {
+pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult {
+    let def_id = body.source.def_id();
     let mut current = def_id;
     loop {
         let predicates = tcx.predicates_of(current);
@@ -23,15 +27,9 @@
                 | ty::PredicateAtom::ConstEvaluatable(..)
                 | ty::PredicateAtom::ConstEquate(..)
                 | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
-                ty::PredicateAtom::ObjectSafe(_) => {
-                    panic!("object safe predicate on function: {:#?}", predicate)
-                }
-                ty::PredicateAtom::ClosureKind(..) => {
-                    panic!("closure kind predicate on function: {:#?}", predicate)
-                }
-                ty::PredicateAtom::Subtype(_) => {
-                    panic!("subtype predicate on function: {:#?}", predicate)
-                }
+                ty::PredicateAtom::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
+                ty::PredicateAtom::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
+                ty::PredicateAtom::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
                 ty::PredicateAtom::Trait(pred, _) => {
                     if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                         continue;
@@ -47,12 +45,12 @@
                                  on const fn parameters are unstable"
                                     .into(),
                             ));
-                        }
+                        },
                         // other kinds of bounds are either tautologies
                         // or cause errors in other passes
                         _ => continue,
                     }
-                }
+                },
             }
         }
         match predicates.parent {
@@ -92,24 +90,23 @@
 
         match ty.kind() {
             ty::Ref(_, _, hir::Mutability::Mut) => {
-                    return Err((span, "mutable references in const fn are unstable".into()));
-            }
+                return Err((span, "mutable references in const fn are unstable".into()));
+            },
             ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
             ty::FnPtr(..) => {
-                    return Err((span, "function pointers in const fn are unstable".into()));
-            }
+                return Err((span, "function pointers in const fn are unstable".into()));
+            },
             ty::Dynamic(preds, _) => {
                 for pred in preds.iter() {
                     match pred.skip_binder() {
-                        ty::ExistentialPredicate::AutoTrait(_)
-                        | ty::ExistentialPredicate::Projection(_) => {
+                        ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
                             return Err((
                                 span,
                                 "trait bounds other than `Sized` \
                                  on const fn parameters are unstable"
                                     .into(),
                             ));
-                        }
+                        },
                         ty::ExistentialPredicate::Trait(trait_ref) => {
                             if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
                                 return Err((
@@ -119,34 +116,23 @@
                                         .into(),
                                 ));
                             }
-                        }
+                        },
                     }
                 }
-            }
-            _ => {}
+            },
+            _ => {},
         }
     }
     Ok(())
 }
 
-fn check_rvalue(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    def_id: DefId,
-    rvalue: &Rvalue<'tcx>,
-    span: Span,
-) -> McfResult {
+fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult {
     match rvalue {
-        Rvalue::ThreadLocalRef(_) => {
-            Err((span, "cannot access thread local storage in const fn".into()))
-        }
-        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
-            check_operand(tcx, operand, span, body)
-        }
-        Rvalue::Len(place)
-        | Rvalue::Discriminant(place)
-        | Rvalue::Ref(_, _, place)
-        | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span,  body),
+        Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
+        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body),
+        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
+            check_place(tcx, *place, span, body)
+        },
         Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
             use rustc_middle::ty::cast::CastTy;
             let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
@@ -154,20 +140,16 @@
             match (cast_in, cast_out) {
                 (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
                     Err((span, "casting pointers to ints is unstable in const fn".into()))
-                }
+                },
                 _ => check_operand(tcx, operand, span, body),
             }
-        }
-        Rvalue::Cast(
-            CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
-            operand,
-            _,
-        ) => check_operand(tcx, operand, span, body),
+        },
+        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => {
+            check_operand(tcx, operand, span, body)
+        },
         Rvalue::Cast(
             CastKind::Pointer(
-                PointerCast::UnsafeFnPointer
-                | PointerCast::ClosureFnPointer(_)
-                | PointerCast::ReifyFnPointer,
+                PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer,
             ),
             _,
             _,
@@ -177,10 +159,7 @@
                 deref_ty.ty
             } else {
                 // We cannot allow this for now.
-                return Err((
-                    span,
-                    "unsizing casts are only allowed for references right now".into(),
-                ));
+                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() {
@@ -191,7 +170,7 @@
                 // We just can't allow trait objects until we have figured out trait method calls.
                 Err((span, "unsizing casts are not allowed in const fn".into()))
             }
-        }
+        },
         // binops are fine on integers
         Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
             check_operand(tcx, lhs, span, body)?;
@@ -200,13 +179,14 @@
             if ty.is_integral() || ty.is_bool() || ty.is_char() {
                 Ok(())
             } else {
-                Err((span, "only int, `bool` and `char` operations are stable in const fn".into()))
+                Err((
+                    span,
+                    "only int, `bool` and `char` operations are stable in const fn".into(),
+                ))
             }
-        }
+        },
         Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
-        Rvalue::NullaryOp(NullOp::Box, _) => {
-            Err((span, "heap allocations are not allowed in const fn".into()))
-        }
+        Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
@@ -214,39 +194,29 @@
             } 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)?;
             }
             Ok(())
-        }
+        },
     }
 }
 
-fn check_statement(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    def_id: DefId,
-    statement: &Statement<'tcx>,
-) -> McfResult {
+fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult {
     let span = statement.source_info.span;
     match &statement.kind {
         StatementKind::Assign(box (place, rval)) => {
-            check_place(tcx, *place, span,  body)?;
+            check_place(tcx, *place, span, body)?;
             check_rvalue(tcx, body, def_id, rval, span)
-        }
+        },
 
-        StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, body),
-
+        StatementKind::FakeRead(_, place) |
         // just an assignment
-        StatementKind::SetDiscriminant { place, .. } => {
-            check_place(tcx, **place, span,  body)
-        }
+        StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
 
-        StatementKind::LlvmInlineAsm { .. } => {
-            Err((span, "cannot use inline assembly in const fn".into()))
-        }
+        StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
 
         // These are all NOPs
         StatementKind::StorageLive(_)
@@ -258,12 +228,7 @@
     }
 }
 
-fn check_operand(
-    tcx: TyCtxt<'tcx>,
-    operand: &Operand<'tcx>,
-    span: Span,
-    body: &Body<'tcx>,
-) -> McfResult {
+fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
     match operand {
         Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
         Operand::Constant(c) => match c.check_static_ptr(tcx) {
@@ -273,14 +238,9 @@
     }
 }
 
-fn check_place(
-    tcx: TyCtxt<'tcx>,
-    place: Place<'tcx>,
-    span: Span,
-    body: &Body<'tcx>,
-) -> McfResult {
+fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
     let mut cursor = place.projection.as_ref();
-    while let &[ref proj_base @ .., elem] = cursor {
+    while let [ref proj_base @ .., elem] = *cursor {
         cursor = proj_base;
         match elem {
             ProjectionElem::Field(..) => {
@@ -288,26 +248,22 @@
                 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()));
+                        return Err((span, "accessing union fields is unstable".into()));
                     }
                 }
-            }
+            },
             ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Deref
-            | ProjectionElem::Index(_) => {}
+            | ProjectionElem::Index(_) => {},
         }
     }
 
     Ok(())
 }
 
-fn check_terminator(
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    terminator: &Terminator<'tcx>,
-) -> McfResult {
+fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>) -> McfResult {
     let span = terminator.source_info.span;
     match &terminator.kind {
         TerminatorKind::FalseEdge { .. }
@@ -317,20 +273,22 @@
         | TerminatorKind::Resume
         | TerminatorKind::Unreachable => Ok(()),
 
-        TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span,  body),
+        TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
         TerminatorKind::DropAndReplace { place, value, .. } => {
-            check_place(tcx, *place, span,  body)?;
+            check_place(tcx, *place, span, body)?;
             check_operand(tcx, value, span, body)
-        }
+        },
 
-        TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
-            check_operand(tcx, discr, span, body)
-        }
+        TerminatorKind::SwitchInt {
+            discr,
+            switch_ty: _,
+            targets: _,
+        } => check_operand(tcx, discr, span, body),
 
         TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
         TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
             Err((span, "const fn generators are unstable".into()))
-        }
+        },
 
         TerminatorKind::Call {
             func,
@@ -342,8 +300,7 @@
         } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
-                if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id)
-                {
+                if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) {
                     return Err((
                         span,
                         format!(
@@ -359,9 +316,7 @@
                 // within const fns. `transmute` is allowed in all other const contexts.
                 // This won't really scale to more intrinsics or functions. Let's allow const
                 // transmutes in const fn before we add more hacks to this.
-                if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic
-                    && tcx.item_name(fn_def_id) == sym::transmute
-                {
+                if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute {
                     return Err((
                         span,
                         "can only call `transmute` from const items, not `const fn`".into(),
@@ -377,14 +332,16 @@
             } else {
                 Err((span, "can only call other const fns within const fn".into()))
             }
-        }
+        },
 
-        TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => {
-            check_operand(tcx, cond, span, body)
-        }
+        TerminatorKind::Assert {
+            cond,
+            expected: _,
+            msg: _,
+            target: _,
+            cleanup: _,
+        } => check_operand(tcx, cond, span, body),
 
-        TerminatorKind::InlineAsm { .. } => {
-            Err((span, "cannot use inline assembly in const fn".into()))
-        }
+        TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/sugg.rs b/src/tools/clippy/clippy_lints/src/utils/sugg.rs
index ec8b7e5..a2a1d10 100644
--- a/src/tools/clippy/clippy_lints/src/utils/sugg.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/sugg.rs
@@ -110,6 +110,7 @@
             | hir::ExprKind::Index(..)
             | hir::ExprKind::InlineAsm(..)
             | hir::ExprKind::LlvmInlineAsm(..)
+            | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Lit(..)
             | hir::ExprKind::Loop(..)
             | hir::ExprKind::MethodCall(..)
@@ -157,6 +158,7 @@
             | ast::ExprKind::Index(..)
             | ast::ExprKind::InlineAsm(..)
             | ast::ExprKind::LlvmInlineAsm(..)
+            | ast::ExprKind::ConstBlock(..)
             | ast::ExprKind::Lit(..)
             | ast::ExprKind::Loop(..)
             | ast::ExprKind::MacCall(..)
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index fac63bc..d9d60ff 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -235,8 +235,19 @@
     }
 
     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
+        fn is_build_script(cx: &EarlyContext<'_>) -> bool {
+            // Cargo sets the crate name for build scripts to `build_script_build`
+            cx.sess
+                .opts
+                .crate_name
+                .as_ref()
+                .map_or(false, |crate_name| crate_name == "build_script_build")
+        }
+
         if mac.path == sym!(println) {
-            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
+            if !is_build_script(cx) {
+                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
+            }
             if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if fmt_str.symbol == Symbol::intern("") {
                     span_lint_and_sugg(
@@ -251,7 +262,9 @@
                 }
             }
         } else if mac.path == sym!(print) {
-            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
+            if !is_build_script(cx) {
+                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
+            }
             if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if check_newlines(&fmt_str) {
                     span_lint_and_then(
diff --git a/src/tools/clippy/clippy_workspace_tests/build.rs b/src/tools/clippy/clippy_workspace_tests/build.rs
new file mode 100644
index 0000000..3507168
--- /dev/null
+++ b/src/tools/clippy/clippy_workspace_tests/build.rs
@@ -0,0 +1,7 @@
+#![deny(clippy::print_stdout)]
+
+fn main() {
+    // Test for #6041
+    println!("Hello");
+    print!("Hello");
+}
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index 21e0f6f..2869c3b 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -189,7 +189,8 @@
 
 * The section of lines prefixed with `///` constitutes the lint documentation
   section. This is the default documentation style and will be displayed
-  [like this][example_lint_page].
+  [like this][example_lint_page]. To render and open this documentation locally
+  in a browser, run `cargo dev serve`.
 * `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
   [lint naming guidelines][lint_naming] here when naming your lint.
   In short, the name should state the thing that is being checked for and
diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md
index c81e7f6..38959e2 100644
--- a/src/tools/clippy/doc/basics.md
+++ b/src/tools/clippy/doc/basics.md
@@ -13,6 +13,7 @@
   - [Setup](#setup)
   - [Building and Testing](#building-and-testing)
   - [`cargo dev`](#cargo-dev)
+  - [PR](#pr)
 
 ## Get the Code
 
@@ -110,3 +111,8 @@
 # (experimental) Setup Clippy to work with rust-analyzer
 cargo dev ra-setup
 ```
+
+## PR
+
+We follow a rustc no merge-commit policy.
+See <https://rustc-dev-guide.rust-lang.org/contributing.html#opening-a-pr>.
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 47315fa..805828e 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -277,9 +277,9 @@
     // If backtraces are enabled, also print the query stack
     let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
 
-    if backtrace {
-        TyCtxt::try_print_query_stack(&handler);
-    }
+    let num_frames = if backtrace { None } else { Some(2) };
+
+    TyCtxt::try_print_query_stack(&handler, num_frames);
 }
 
 fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> {
@@ -357,7 +357,7 @@
                 args.extend(vec!["--sysroot".into(), sys_root]);
             };
 
-            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None);
+            return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
         }
 
         if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -420,6 +420,6 @@
         let mut default = DefaultCallbacks;
         let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
             if clippy_enabled { &mut clippy } else { &mut default };
-        rustc_driver::run_compiler(&args, callbacks, None, None)
+        rustc_driver::RunCompiler::new(&args, callbacks).run()
     }))
 }
diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs
index 9603023..ce3d0ef 100644
--- a/src/tools/clippy/src/lintlist/mod.rs
+++ b/src/tools/clippy/src/lintlist/mod.rs
@@ -110,7 +110,7 @@
     },
     Lint {
         name: "borrow_interior_mutable_const",
-        group: "correctness",
+        group: "style",
         desc: "referencing `const` with interior mutability",
         deprecation: None,
         module: "non_copy_const",
@@ -334,7 +334,7 @@
     },
     Lint {
         name: "declare_interior_mutable_const",
-        group: "correctness",
+        group: "style",
         desc: "declaring `const` with interior mutability",
         deprecation: None,
         module: "non_copy_const",
@@ -382,6 +382,13 @@
         module: "derive",
     },
     Lint {
+        name: "disallowed_method",
+        group: "nursery",
+        desc: "use of a disallowed method call",
+        deprecation: None,
+        module: "disallowed_method",
+    },
+    Lint {
         name: "diverging_sub_expression",
         group: "complexity",
         desc: "whether an expression contains a diverging sub expression",
@@ -424,13 +431,6 @@
         module: "double_parens",
     },
     Lint {
-        name: "drop_bounds",
-        group: "correctness",
-        desc: "bounds of the form `T: Drop` are useless",
-        deprecation: None,
-        module: "drop_bounds",
-    },
-    Lint {
         name: "drop_copy",
         group: "correctness",
         desc: "calls to `std::mem::drop` with a value that implements Copy",
@@ -893,6 +893,20 @@
         module: "attrs",
     },
     Lint {
+        name: "inline_asm_x86_att_syntax",
+        group: "restriction",
+        desc: "prefer Intel x86 assembly syntax",
+        deprecation: None,
+        module: "asm_syntax",
+    },
+    Lint {
+        name: "inline_asm_x86_intel_syntax",
+        group: "restriction",
+        desc: "prefer AT&T x86 assembly syntax",
+        deprecation: None,
+        module: "asm_syntax",
+    },
+    Lint {
         name: "inline_fn_without_body",
         group: "correctness",
         desc: "use of `#[inline]` on trait methods without bodies",
@@ -949,6 +963,13 @@
         module: "types",
     },
     Lint {
+        name: "invisible_characters",
+        group: "correctness",
+        desc: "using an invisible character in a string literal, which is confusing",
+        deprecation: None,
+        module: "unicode",
+    },
+    Lint {
         name: "items_after_statements",
         group: "pedantic",
         desc: "blocks where an item comes after a statement",
@@ -1867,7 +1888,7 @@
     },
     Lint {
         name: "rc_buffer",
-        group: "perf",
+        group: "restriction",
         desc: "shared ownership of a buffer type",
         deprecation: None,
         module: "types",
@@ -2140,7 +2161,7 @@
     },
     Lint {
         name: "string_lit_as_bytes",
-        group: "style",
+        group: "nursery",
         desc: "calling `as_bytes` on a string literal instead of using a byte string literal",
         deprecation: None,
         module: "strings",
@@ -2790,13 +2811,6 @@
         module: "misc",
     },
     Lint {
-        name: "zero_width_space",
-        group: "correctness",
-        desc: "using a zero-width space in a string literal, which is confusing",
-        deprecation: None,
-        module: "unicode",
-    },
-    Lint {
         name: "zst_offset",
         group: "correctness",
         desc: "Check for offset calculations on raw pointers to zero-sized types",
diff --git a/src/tools/clippy/tests/cargo/mod.rs b/src/tools/clippy/tests/cargo/mod.rs
index 3c38534..a8f3e31 100644
--- a/src/tools/clippy/tests/cargo/mod.rs
+++ b/src/tools/clippy/tests/cargo/mod.rs
@@ -1,27 +1,24 @@
-use lazy_static::lazy_static;
 use std::env;
+use std::lazy::SyncLazy;
 use std::path::PathBuf;
 
-lazy_static! {
-    pub static ref CARGO_TARGET_DIR: PathBuf = {
-        match env::var_os("CARGO_TARGET_DIR") {
-            Some(v) => v.into(),
-            None => env::current_dir().unwrap().join("target"),
+pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
+    Some(v) => v.into(),
+    None => env::current_dir().unwrap().join("target"),
+});
+
+pub static TARGET_LIB: SyncLazy<PathBuf> = SyncLazy::new(|| {
+    if let Some(path) = option_env!("TARGET_LIBS") {
+        path.into()
+    } else {
+        let mut dir = CARGO_TARGET_DIR.clone();
+        if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
+            dir.push(target);
         }
-    };
-    pub static ref TARGET_LIB: PathBuf = {
-        if let Some(path) = option_env!("TARGET_LIBS") {
-            path.into()
-        } else {
-            let mut dir = CARGO_TARGET_DIR.clone();
-            if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
-                dir.push(target);
-            }
-            dir.push(env!("PROFILE"));
-            dir
-        }
-    };
-}
+        dir.push(env!("PROFILE"));
+        dir
+    }
+});
 
 #[must_use]
 pub fn is_rustc_test_suite() -> bool {
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 6978237..0e8f768 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -1,4 +1,5 @@
 #![feature(test)] // compiletest_rs requires this attribute
+#![feature(once_cell)]
 
 use compiletest_rs as compiletest;
 use compiletest_rs::common::Mode as TestMode;
@@ -71,7 +72,7 @@
     }
 
     config.target_rustcflags = Some(format!(
-        "-L {0} -L {1} -Dwarnings -Zui-testing {2}",
+        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
         host_lib().join("deps").display(),
         cargo::TARGET_LIB.join("deps").display(),
         third_party_crates(),
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 81af3d3..48e0478 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -1,15 +1,14 @@
 // Dogfood cannot run on Windows
 #![cfg(not(windows))]
+#![feature(once_cell)]
 
-use lazy_static::lazy_static;
+use std::lazy::SyncLazy;
 use std::path::PathBuf;
 use std::process::Command;
 
 mod cargo;
 
-lazy_static! {
-    static ref CLIPPY_PATH: PathBuf = cargo::TARGET_LIB.join("cargo-clippy");
-}
+static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy"));
 
 #[test]
 fn dogfood_clippy() {
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml
new file mode 100644
index 0000000..a1f515e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml
@@ -0,0 +1 @@
+disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
new file mode 100644
index 0000000..3d3f072
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
@@ -0,0 +1,13 @@
+#![warn(clippy::disallowed_method)]
+
+extern crate regex;
+use regex::Regex;
+
+fn main() {
+    let a = vec![1, 2, 3, 4];
+    let re = Regex::new(r"ab.*c").unwrap();
+
+    re.is_match("abc");
+
+    a.iter().sum::<i32>();
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
new file mode 100644
index 0000000..ed91b5a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
@@ -0,0 +1,16 @@
+error: use of a disallowed method `regex::re_unicode::Regex::is_match`
+  --> $DIR/conf_disallowed_method.rs:10:5
+   |
+LL |     re.is_match("abc");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::disallowed-method` implied by `-D warnings`
+
+error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
+  --> $DIR/conf_disallowed_method.rs:12:5
+   |
+LL |     a.iter().sum::<i32>();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
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 6fbba01..103ec27 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
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/asm_syntax.rs b/src/tools/clippy/tests/ui/asm_syntax.rs
new file mode 100644
index 0000000..658cae3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/asm_syntax.rs
@@ -0,0 +1,31 @@
+#![feature(asm)]
+// only-x86_64
+
+#[warn(clippy::inline_asm_x86_intel_syntax)]
+mod warn_intel {
+    pub(super) unsafe fn use_asm() {
+        asm!("");
+        asm!("", options());
+        asm!("", options(nostack));
+        asm!("", options(att_syntax));
+        asm!("", options(nostack, att_syntax));
+    }
+}
+
+#[warn(clippy::inline_asm_x86_att_syntax)]
+mod warn_att {
+    pub(super) unsafe fn use_asm() {
+        asm!("");
+        asm!("", options());
+        asm!("", options(nostack));
+        asm!("", options(att_syntax));
+        asm!("", options(nostack, att_syntax));
+    }
+}
+
+fn main() {
+    unsafe {
+        warn_att::use_asm();
+        warn_intel::use_asm();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/asm_syntax.stderr b/src/tools/clippy/tests/ui/asm_syntax.stderr
new file mode 100644
index 0000000..27b5116
--- /dev/null
+++ b/src/tools/clippy/tests/ui/asm_syntax.stderr
@@ -0,0 +1,44 @@
+error: Intel x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:7:9
+   |
+LL |         asm!("");
+   |         ^^^^^^^^^
+   |
+   = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings`
+   = help: use AT&T x86 assembly syntax
+
+error: Intel x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:8:9
+   |
+LL |         asm!("", options());
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use AT&T x86 assembly syntax
+
+error: Intel x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:9:9
+   |
+LL |         asm!("", options(nostack));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use AT&T x86 assembly syntax
+
+error: AT&T x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:21:9
+   |
+LL |         asm!("", options(att_syntax));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings`
+   = help: use Intel x86 assembly syntax
+
+error: AT&T x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:22:9
+   |
+LL |         asm!("", options(nostack, att_syntax));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use Intel x86 assembly syntax
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs
index 908d063..8df6e19 100644
--- a/src/tools/clippy/tests/ui/attrs.rs
+++ b/src/tools/clippy/tests/ui/attrs.rs
@@ -1,9 +1,5 @@
 #![warn(clippy::inline_always, clippy::deprecated_semver)]
 #![allow(clippy::assertions_on_constants)]
-// Test that the whole restriction group is not enabled
-#![warn(clippy::restriction)]
-#![deny(clippy::restriction)]
-#![forbid(clippy::restriction)]
 #![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)]
 
 #[inline(always)]
diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr
index ef4b89e..df4e9e2 100644
--- a/src/tools/clippy/tests/ui/attrs.stderr
+++ b/src/tools/clippy/tests/ui/attrs.stderr
@@ -1,5 +1,5 @@
 error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
-  --> $DIR/attrs.rs:9:1
+  --> $DIR/attrs.rs:5:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@
    = note: `-D clippy::inline-always` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:29:14
+  --> $DIR/attrs.rs:25:14
    |
 LL | #[deprecated(since = "forever")]
    |              ^^^^^^^^^^^^^^^^^
@@ -15,35 +15,10 @@
    = note: `-D clippy::deprecated-semver` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:32:14
+  --> $DIR/attrs.rs:28:14
    |
 LL | #[deprecated(since = "1")]
    |              ^^^^^^^^^^^
 
-error: restriction lints are not meant to be all enabled
-  --> $DIR/attrs.rs:4:9
-   |
-LL | #![warn(clippy::restriction)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
-   = help: try enabling only the lints you really need
-
-error: restriction lints are not meant to be all enabled
-  --> $DIR/attrs.rs:5:9
-   |
-LL | #![deny(clippy::restriction)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try enabling only the lints you really need
-
-error: restriction lints are not meant to be all enabled
-  --> $DIR/attrs.rs:6:11
-   |
-LL | #![forbid(clippy::restriction)]
-   |           ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try enabling only the lints you really need
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index e6626d5..e370a98 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -1,7 +1,9 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(repr128, proc_macro_hygiene, proc_macro_quote)]
+#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
+#![allow(incomplete_features)]
 #![allow(clippy::useless_conversion)]
 
 extern crate proc_macro;
@@ -11,7 +13,11 @@
 use proc_macro::TokenStream;
 use quote::{quote, quote_spanned};
 use syn::parse_macro_input;
-use syn::{parse_quote, ItemTrait, TraitItem};
+use syn::spanned::Spanned;
+use syn::token::Star;
+use syn::{
+    parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type,
+};
 
 #[proc_macro_attribute]
 pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
@@ -35,3 +41,56 @@
     }
     TokenStream::from(quote!(#item))
 }
+
+#[proc_macro_attribute]
+pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream {
+    fn make_name(count: usize) -> String {
+        format!("'life{}", count)
+    }
+
+    fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> {
+        let arg = sig.inputs.first_mut()?;
+        if let FnArg::Typed(PatType { pat, .. }) = arg {
+            if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
+                if ident == "self" {
+                    return Some(arg);
+                }
+            }
+        }
+        None
+    }
+
+    let mut elided = 0;
+    let mut item = parse_macro_input!(input as ItemImpl);
+
+    // Look for methods having arbitrary self type taken by &mut ref
+    for inner in &mut item.items {
+        if let ImplItem::Method(method) = inner {
+            if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) {
+                if let box Type::Reference(reference) = &mut pat_type.ty {
+                    // Target only unnamed lifetimes
+                    let name = match &reference.lifetime {
+                        Some(lt) if lt.ident == "_" => make_name(elided),
+                        None => make_name(elided),
+                        _ => continue,
+                    };
+                    elided += 1;
+
+                    // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
+                    // In order to avoid adding the dependency, get a default span from a non-existent token.
+                    // A default span is needed to mark the code as coming from expansion.
+                    let span = Star::default().span();
+
+                    // Replace old lifetime with the named one
+                    let lifetime = Lifetime::new(&name, span);
+                    reference.lifetime = Some(parse_quote!(#lifetime));
+
+                    // Add lifetime to the generics of the method
+                    method.sig.generics.params.push(parse_quote!(#lifetime));
+                }
+            }
+        }
+    }
+
+    TokenStream::from(quote!(#item))
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
index 05ffb55..cd5a5ae 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -1,7 +1,9 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
 #![feature(repr128, proc_macro_quote)]
+#![allow(incomplete_features)]
 
 extern crate proc_macro;
 
diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs
new file mode 100644
index 0000000..d055f17
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs
@@ -0,0 +1,8 @@
+#![warn(clippy::blanket_clippy_restriction_lints)]
+
+//! Test that the whole restriction group is not enabled
+#![warn(clippy::restriction)]
+#![deny(clippy::restriction)]
+#![forbid(clippy::restriction)]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
new file mode 100644
index 0000000..537557f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
@@ -0,0 +1,27 @@
+error: restriction lints are not meant to be all enabled
+  --> $DIR/blanket_clippy_restriction_lints.rs:4:9
+   |
+LL | #![warn(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/blanket_clippy_restriction_lints.rs:5:9
+   |
+LL | #![deny(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/blanket_clippy_restriction_lints.rs:6:11
+   |
+LL | #![forbid(clippy::restriction)]
+   |           ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
index 4bb8337..948deba 100644
--- a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
+++ b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1698
 
 pub trait Trait {
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
index 086548e..ed8e7a7 100644
--- a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
@@ -1,3 +1,4 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 // ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro
 // crates. If we don't set this, compiletest will override the `crate_type` attribute below and
@@ -5,6 +6,7 @@
 // contain a proc-macro.
 
 #![feature(repr128)]
+#![allow(incomplete_features)]
 #![crate_type = "proc-macro"]
 
 extern crate proc_macro;
diff --git a/src/tools/clippy/tests/ui/crashes/cc_seme.rs b/src/tools/clippy/tests/ui/crashes/cc_seme.rs
index c48c7e9..98588be 100644
--- a/src/tools/clippy/tests/ui/crashes/cc_seme.rs
+++ b/src/tools/clippy/tests/ui/crashes/cc_seme.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[allow(dead_code)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/478
diff --git a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
index db1fa87..dca32aa 100644
--- a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
+++ b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 #![allow(unused_imports)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1588.rs b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
index 15d0f70..b0a3d11 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1588.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1588
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
index 1ca6b69..81af889 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, unused_variables)]
 
 /// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1969.rs b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
index 837ec9d..96a8fe6 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1969.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1969
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2499.rs b/src/tools/clippy/tests/ui/crashes/ice-2499.rs
index ffef163..45b3b18 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2499.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2499.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)]
 
 /// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2594.rs b/src/tools/clippy/tests/ui/crashes/ice-2594.rs
index ac19f19..3f3986b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2594.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2594.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, unused_variables)]
 
 /// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2727.rs b/src/tools/clippy/tests/ui/crashes/ice-2727.rs
index d832c28..56024ab 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2727.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2727.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2727
 
 pub fn f(new: fn()) {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
index 9e5e299..f1a229f 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2760.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(
     unused_variables,
     clippy::blacklisted_name,
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.rs b/src/tools/clippy/tests/ui/crashes/ice-2774.rs
index 47f8e3b..d44b0fa 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2774.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2774.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 use std::collections::HashSet;
 
 // See rust-lang/rust-clippy#2774.
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
new file mode 100644
index 0000000..0c2d48f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
@@ -0,0 +1,10 @@
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/ice-2774.rs:15:1
+   |
+LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2862.rs b/src/tools/clippy/tests/ui/crashes/ice-2862.rs
index 47324ce..8326e36 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2862.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2862.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2862
 
 pub trait FooMap {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2865.rs b/src/tools/clippy/tests/ui/crashes/ice-2865.rs
index c4f6c0f..6b1ceb5 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2865.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2865.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[allow(dead_code)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2865
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3151.rs b/src/tools/clippy/tests/ui/crashes/ice-3151.rs
index ffad2d0..fef4d7d 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3151.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3151.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2865
 
 #[derive(Clone)]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
index 95c7dff..7d62e31 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::all)]
 #![allow(clippy::blacklisted_name)]
 #![allow(unused)]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3741.rs b/src/tools/clippy/tests/ui/crashes/ice-3741.rs
index a548415..1253ddc 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3741.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3741.rs
@@ -1,5 +1,4 @@
 // aux-build:proc_macro_crash.rs
-// run-pass
 
 #![warn(clippy::suspicious_else_formatting)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3747.rs b/src/tools/clippy/tests/ui/crashes/ice-3747.rs
index d0b44eb..cdf018c 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3747.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3747.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/3747
 
 macro_rules! a {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4727.rs b/src/tools/clippy/tests/ui/crashes/ice-4727.rs
index cdb59ca..2a4bc83 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-4727.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-4727.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::use_self)]
 
 #[path = "auxiliary/ice-4727-aux.rs"]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4760.rs b/src/tools/clippy/tests/ui/crashes/ice-4760.rs
index ead67d5..08b0696 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-4760.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-4760.rs
@@ -1,4 +1,3 @@
-// run-pass
 const COUNT: usize = 2;
 struct Thing;
 trait Dummy {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-700.rs b/src/tools/clippy/tests/ui/crashes/ice-700.rs
index b06df83..0cbceed 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-700.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-700.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/700
diff --git a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
index e02eb28..30e4b11 100644
--- a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1336
diff --git a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
index 4ef992b..2f91329 100644
--- a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::comparison_chain)]
 #![deny(clippy::if_same_then_else)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/issue-825.rs b/src/tools/clippy/tests/ui/crashes/issue-825.rs
index 3d4a88a..05696e3 100644
--- a/src/tools/clippy/tests/ui/crashes/issue-825.rs
+++ b/src/tools/clippy/tests/ui/crashes/issue-825.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(warnings)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/825
diff --git a/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
index c4acd5c..bb238c8 100644
--- a/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
+++ b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code)]
 
 /// Issue: https://github.com/rust-lang/rust-clippy/issues/2596
diff --git a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
index 848f0ea..94c9396 100644
--- a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
+++ b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::match_same_arms)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2427
diff --git a/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs b/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
index d8fbaa5..a238e78 100644
--- a/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
+++ b/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)]
 #![allow(dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
index 48507ef..4f61c76 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
+++ b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[deny(clippy::all)]
 #[derive(Debug)]
 pub enum Error {
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
index bd1fa4a..676564b 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::needless_lifetimes)]
 #![allow(dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
new file mode 100644
index 0000000..d68bbe7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
@@ -0,0 +1,14 @@
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes_impl_trait.rs:15:5
+   |
+LL |     fn baz<'a>(&'a self) -> impl Foo + 'a {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/needless_lifetimes_impl_trait.rs:1:9
+   |
+LL | #![deny(clippy::needless_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
index f79d9ab..c746849 100644
--- a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
+++ b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[macro_use]
 extern crate clippy_mini_macro_test;
 
diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs
index 3d5063d..a41bcb3 100644
--- a/src/tools/clippy/tests/ui/crashes/regressions.rs
+++ b/src/tools/clippy/tests/ui/crashes/regressions.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::blacklisted_name)]
 
 pub fn foo(bar: *const u8) {
diff --git a/src/tools/clippy/tests/ui/crashes/returns.rs b/src/tools/clippy/tests/ui/crashes/returns.rs
index f2153ef..8021ed4 100644
--- a/src/tools/clippy/tests/ui/crashes/returns.rs
+++ b/src/tools/clippy/tests/ui/crashes/returns.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1346
 
 #[deny(warnings)]
diff --git a/src/tools/clippy/tests/ui/crashes/single-match-else.rs b/src/tools/clippy/tests/ui/crashes/single-match-else.rs
index 3a4bbe3..1ba7ac0 100644
--- a/src/tools/clippy/tests/ui/crashes/single-match-else.rs
+++ b/src/tools/clippy/tests/ui/crashes/single-match-else.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::single_match_else)]
 
 //! Test for https://github.com/rust-lang/rust-clippy/issues/1588
diff --git a/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
index 2bb95c1..60105a8 100644
--- a/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
+++ b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![feature(trivial_bounds)]
 #![allow(unused, trivial_bounds)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
index 265017c..6d2124c 100644
--- a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
+++ b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::useless_attribute)] //issue #2910
 
 #[macro_use]
diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr
index a9a65a3..a1b8e2e 100644
--- a/src/tools/clippy/tests/ui/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr
@@ -9,3 +9,5 @@
 
 note: Clippy version: foo
 
+query stack during panic:
+end of query stack
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index 3eefb23..9e32fe3 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -8,5 +8,6 @@
 #[warn(clippy::into_iter_on_array)]
 #[warn(clippy::unused_label)]
 #[warn(clippy::regex_macro)]
+#[warn(clippy::drop_bounds)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index a80e2bf..d3400a7 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -60,11 +60,17 @@
 LL | #[warn(clippy::regex_macro)]
    |        ^^^^^^^^^^^^^^^^^^^
 
+error: lint `clippy::drop_bounds` has been removed: `this lint has been uplifted to rustc and is now called `drop_bounds``
+  --> $DIR/deprecated.rs:11:8
+   |
+LL | #[warn(clippy::drop_bounds)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
 error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
   --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::str_to_string)]
    |        ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/drop_bounds.rs b/src/tools/clippy/tests/ui/drop_bounds.rs
deleted file mode 100644
index 6d6a9dc..0000000
--- a/src/tools/clippy/tests/ui/drop_bounds.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![allow(unused)]
-fn foo<T: Drop>() {}
-fn bar<T>()
-where
-    T: Drop,
-{
-}
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/drop_bounds.stderr b/src/tools/clippy/tests/ui/drop_bounds.stderr
deleted file mode 100644
index 8208c0e..0000000
--- a/src/tools/clippy/tests/ui/drop_bounds.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error: bounds of the form `T: Drop` are useless, use `std::mem::needs_drop` to detect if a type has drop glue
-  --> $DIR/drop_bounds.rs:2:11
-   |
-LL | fn foo<T: Drop>() {}
-   |           ^^^^
-   |
-   = note: `#[deny(clippy::drop_bounds)]` on by default
-
-error: bounds of the form `T: Drop` are useless, use `std::mem::needs_drop` to detect if a type has drop glue
-  --> $DIR/drop_bounds.rs:5:8
-   |
-LL |     T: Drop,
-   |        ^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui/escape_analysis.rs b/src/tools/clippy/tests/ui/escape_analysis.rs
index c0a52d8..0700448 100644
--- a/src/tools/clippy/tests/ui/escape_analysis.rs
+++ b/src/tools/clippy/tests/ui/escape_analysis.rs
@@ -174,3 +174,11 @@
         };
     }
 }
+
+/// Issue #5542
+///
+/// This shouldn't warn for `boxed_local` as it is intended to called from non-Rust code.
+pub extern "C" fn do_not_warn_me(_c_pointer: Box<String>) -> () {}
+
+#[rustfmt::skip] // Forces rustfmt to not add ABI
+pub extern fn do_not_warn_me_no_abi(_c_pointer: Box<String>) -> () {}
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index aa6ef16..81d8221 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -38,54 +38,54 @@
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             if ch == 'a' {
                 continue;
             }
             count += 1;
-            println!("{}", count);
         }
 
         // should not trigger the lint because the count is conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             if ch == 'a' {
                 count += 1;
             }
-            println!("{}", count);
         }
 
         // should trigger the lint because the count is not conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             if ch == 'a' {
                 continue;
             }
-            println!("{}", count);
         }
 
         // should trigger the lint because the count is not conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             for i in 0..2 {
                 let _ = 123;
             }
-            println!("{}", count);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             for i in 0..2 {
                 count += 1;
             }
-            println!("{}", count);
         }
     }
 }
@@ -96,30 +96,30 @@
         let mut skips = 0;
         let erasures = vec![];
         for i in 0..10 {
+            println!("{}", skips);
             while erasures.contains(&(i + skips)) {
                 skips += 1;
             }
-            println!("{}", skips);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
+            println!("{}", skips);
             let mut j = 0;
             while j < 5 {
                 skips += 1;
                 j += 1;
             }
-            println!("{}", skips);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
+            println!("{}", skips);
             for j in 0..5 {
                 skips += 1;
             }
-            println!("{}", skips);
         }
     }
 }
@@ -145,3 +145,16 @@
         let _closure = || println!("index: {}", index);
     }
 }
+
+mod issue_4677 {
+    pub fn test() {
+        let slice = &[1, 2, 3];
+
+        // should not trigger the lint because the count is used after incremented
+        let mut count = 0;
+        for _i in slice {
+            count += 1;
+            println!("{}", count);
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
index b75f109..dd683e7 100644
--- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
+++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
@@ -40,4 +40,8 @@
     // Ignore literals in macros
     let _ = mac1!();
     let _ = mac2!();
+
+    // Issue #6096
+    // Allow separating exponent with '_'
+    let _ = 1.025_011_10_E0;
 }
diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
index 79ce38b..d5d27c8 100644
--- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
+++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
@@ -40,4 +40,8 @@
     // Ignore literals in macros
     let _ = mac1!();
     let _ = mac2!();
+
+    // Issue #6096
+    // Allow separating exponent with '_'
+    let _ = 1.025_011_10_E0;
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
index baee773..70cdb06 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+#![allow(
+    dead_code,
+    unused_variables,
+    clippy::excessive_precision,
+    clippy::inconsistent_digit_grouping
+)]
 
 fn main() {
     let fail14 = 2_i32;
@@ -12,13 +17,13 @@
     let fail20 = 2_i8; //
     let fail21 = 4_i16; //
 
-    let fail24 = 12.34_f64;
+    let ok24 = 12.34_64;
     let fail25 = 1E2_f32;
     let fail26 = 43E7_f64;
     let fail27 = 243E17_f32;
     #[allow(overflowing_literals)]
     let fail28 = 241_251_235E723_f64;
-    let fail29 = 42_279.911_f32;
+    let ok29 = 42279.911_32;
 
     let _ = 1.123_45E1_f32;
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
index 6de447f..729990a 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+#![allow(
+    dead_code,
+    unused_variables,
+    clippy::excessive_precision,
+    clippy::inconsistent_digit_grouping
+)]
 
 fn main() {
     let fail14 = 2_32;
@@ -12,13 +17,13 @@
     let fail20 = 2__8; //
     let fail21 = 4___16; //
 
-    let fail24 = 12.34_64;
+    let ok24 = 12.34_64;
     let fail25 = 1E2_32;
     let fail26 = 43E7_64;
     let fail27 = 243E17_32;
     #[allow(overflowing_literals)]
     let fail28 = 241251235E723_64;
-    let fail29 = 42279.911_32;
+    let ok29 = 42279.911_32;
 
     let _ = 1.12345E1_32;
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
index 48a7ae9..b338b8a 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
@@ -1,5 +1,5 @@
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:6:18
+  --> $DIR/mistyped_literal_suffix.rs:11:18
    |
 LL |     let fail14 = 2_32;
    |                  ^^^^ help: did you mean to write: `2_i32`
@@ -7,76 +7,64 @@
    = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:7:18
+  --> $DIR/mistyped_literal_suffix.rs:12:18
    |
 LL |     let fail15 = 4_64;
    |                  ^^^^ help: did you mean to write: `4_i64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:8:18
+  --> $DIR/mistyped_literal_suffix.rs:13:18
    |
 LL |     let fail16 = 7_8; //
    |                  ^^^ help: did you mean to write: `7_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:9:18
+  --> $DIR/mistyped_literal_suffix.rs:14:18
    |
 LL |     let fail17 = 23_16; //
    |                  ^^^^^ help: did you mean to write: `23_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:12:18
+  --> $DIR/mistyped_literal_suffix.rs:17:18
    |
 LL |     let fail20 = 2__8; //
    |                  ^^^^ help: did you mean to write: `2_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:13:18
+  --> $DIR/mistyped_literal_suffix.rs:18:18
    |
 LL |     let fail21 = 4___16; //
    |                  ^^^^^^ help: did you mean to write: `4_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:15:18
-   |
-LL |     let fail24 = 12.34_64;
-   |                  ^^^^^^^^ help: did you mean to write: `12.34_f64`
-
-error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:16:18
+  --> $DIR/mistyped_literal_suffix.rs:21:18
    |
 LL |     let fail25 = 1E2_32;
    |                  ^^^^^^ help: did you mean to write: `1E2_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:17:18
+  --> $DIR/mistyped_literal_suffix.rs:22:18
    |
 LL |     let fail26 = 43E7_64;
    |                  ^^^^^^^ help: did you mean to write: `43E7_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:18:18
+  --> $DIR/mistyped_literal_suffix.rs:23:18
    |
 LL |     let fail27 = 243E17_32;
    |                  ^^^^^^^^^ help: did you mean to write: `243E17_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:20:18
+  --> $DIR/mistyped_literal_suffix.rs:25:18
    |
 LL |     let fail28 = 241251235E723_64;
    |                  ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:21:18
-   |
-LL |     let fail29 = 42279.911_32;
-   |                  ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32`
-
-error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:23:13
+  --> $DIR/mistyped_literal_suffix.rs:28:13
    |
 LL |     let _ = 1.12345E1_32;
    |             ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
 
-error: aborting due to 13 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs
new file mode 100644
index 0000000..a39d961
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs
@@ -0,0 +1,45 @@
+// aux-build:proc_macro_attr.rs
+
+#![warn(clippy::needless_arbitrary_self_type)]
+
+#[macro_use]
+extern crate proc_macro_attr;
+
+mod issue_6089 {
+    // Check that we don't lint if the `self` parameter comes from expansion
+
+    macro_rules! test_from_expansion {
+        () => {
+            trait T1 {
+                fn test(self: &Self);
+            }
+
+            struct S1 {}
+
+            impl T1 for S1 {
+                fn test(self: &Self) {}
+            }
+        };
+    }
+
+    test_from_expansion!();
+
+    // If only the lifetime name comes from expansion we will lint, but the suggestion will have
+    // placeholders and will not be applied automatically, as we can't reliably know the original name.
+    // This specific case happened with async_trait.
+
+    trait T2 {
+        fn call_with_mut_self(&mut self);
+    }
+
+    struct S2 {}
+
+    // The method's signature will be expanded to:
+    //  fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
+    #[rename_my_lifetimes]
+    impl T2 for S2 {
+        fn call_with_mut_self(self: &mut Self) {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr
new file mode 100644
index 0000000..44a0e6d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr
@@ -0,0 +1,10 @@
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31
+   |
+LL |         fn call_with_mut_self(self: &mut Self) {}
+   |                               ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self`
+   |
+   = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 913cd00..d482d46 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -259,4 +259,102 @@
     }
 }
 
+mod issue2944 {
+    trait Foo {}
+    struct Bar {}
+    struct Baz<'a> {
+        bar: &'a Bar,
+    }
+
+    impl<'a> Foo for Baz<'a> {}
+    impl Bar {
+        fn baz<'a>(&'a self) -> impl Foo + 'a {
+            Baz { bar: self }
+        }
+    }
+}
+
+mod nested_elision_sites {
+    // issue #issue2944
+
+    // closure trait bounds subject to nested elision
+    // don't lint because they refer to outer lifetimes
+    fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+        move || i
+    }
+    fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
+        move || i
+    }
+    fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
+        move || i
+    }
+
+    // don't lint
+    fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
+        f()
+    }
+    fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+        move || i
+    }
+    // lint
+    fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
+        f(i)
+    }
+    fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
+        f()
+    }
+    // lint
+    fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
+    where
+        T: Fn() -> &'a i32,
+    {
+        f()
+    }
+    // lint
+    fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
+    where
+        T: Fn(&i32) -> &i32,
+    {
+        f(i)
+    }
+
+    // don't lint
+    fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
+        f(i)
+    }
+    fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
+        |i| i
+    }
+    // lint
+    fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
+        |f| 42
+    }
+    fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
+        |f| ()
+    }
+
+    // lint
+    fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
+        |f| 42
+    }
+    fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
+        |f| ()
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index d3a360e..c8a2e8b 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -102,5 +102,53 @@
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 17 previous errors
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:271:9
+   |
+LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:300:5
+   |
+LL |     fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:303:5
+   |
+LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:312:5
+   |
+LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:324:5
+   |
+LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:339:5
+   |
+LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:352:5
+   |
+LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:355:5
+   |
+LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_range_loop2.rs b/src/tools/clippy/tests/ui/needless_range_loop2.rs
index a82b115..7633316 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop2.rs
+++ b/src/tools/clippy/tests/ui/needless_range_loop2.rs
@@ -82,6 +82,20 @@
     for i in 1..3 {
         println!("{}", arr[i]);
     }
+
+    // Fix #5945
+    let mut vec = vec![1, 2, 3, 4];
+    for i in 0..vec.len() - 1 {
+        vec[i] += 1;
+    }
+    let mut vec = vec![1, 2, 3, 4];
+    for i in vec.len() - 3..vec.len() {
+        vec[i] += 1;
+    }
+    let mut vec = vec![1, 2, 3, 4];
+    for i in vec.len() - 3..vec.len() - 1 {
+        vec[i] += 1;
+    }
 }
 
 mod issue2277 {
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 5fb5686..2045ffd 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -58,6 +58,12 @@
     let without_default = Some(Foo);
     without_default.unwrap_or_else(Foo::new);
 
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert_with(String::new);
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert_with(String::new);
+
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or_else(|| "".to_owned());
 
@@ -110,23 +116,4 @@
     Some(())
 }
 
-// Issue 5886 - const fn (with no arguments)
-pub fn skip_const_fn_with_no_args() {
-    const fn foo() -> Option<i32> {
-        Some(42)
-    }
-    let _ = None.or(foo());
-
-    // See issue #5693.
-    let mut map = std::collections::HashMap::new();
-    map.insert(1, vec![1]);
-    map.entry(1).or_insert(vec![]);
-
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-}
-
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 737b0f7..522f31b 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -58,6 +58,12 @@
     let without_default = Some(Foo);
     without_default.unwrap_or(Foo::new());
 
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert(String::new());
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert(String::new());
+
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or("".to_owned());
 
@@ -110,23 +116,4 @@
     Some(())
 }
 
-// Issue 5886 - const fn (with no arguments)
-pub fn skip_const_fn_with_no_args() {
-    const fn foo() -> Option<i32> {
-        Some(42)
-    }
-    let _ = None.or(foo());
-
-    // See issue #5693.
-    let mut map = std::collections::HashMap::new();
-    map.insert(1, vec![1]);
-    map.entry(1).or_insert(vec![]);
-
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-}
-
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index b8a4369..bc5978b5 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -60,23 +60,35 @@
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
 
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:62:19
+   |
+LL |     map.entry(42).or_insert(String::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:65:21
+   |
+LL |     btree.entry(42).or_insert(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
 error: use of `unwrap_or` followed by a function call
-  --> $DIR/or_fun_call.rs:62:21
+  --> $DIR/or_fun_call.rs:68:21
    |
 LL |     let _ = stringy.unwrap_or("".to_owned());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:87:35
+  --> $DIR/or_fun_call.rs:93:35
    |
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:91:10
+  --> $DIR/or_fun_call.rs:97:10
    |
 LL |         .or(Some(Bar(b, Duration::from_secs(2))));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/print_stdout_build_script.rs b/src/tools/clippy/tests/ui/print_stdout_build_script.rs
new file mode 100644
index 0000000..997ebef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print_stdout_build_script.rs
@@ -0,0 +1,12 @@
+// compile-flags: --crate-name=build_script_build
+
+#![warn(clippy::print_stdout)]
+
+fn main() {
+    // Fix #6041
+    //
+    // The `print_stdout` lint shouldn't emit in `build.rs`
+    // as these methods are used for the build script.
+    println!("Hello");
+    print!("Hello");
+}
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
index 9767e5b..f7f3b19 100644
--- a/src/tools/clippy/tests/ui/regex.rs
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -71,6 +71,9 @@
     let non_trivial_ends_with = Regex::new("foo|bar");
     let non_trivial_binary = BRegex::new("foo|bar");
     let non_trivial_binary_builder = BRegexBuilder::new("foo|bar");
+
+    // #6005: unicode classes in bytes::Regex
+    let a_byte_of_unicode = BRegex::new(r"\p{C}");
 }
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs
index 27db959..1f596c3 100644
--- a/src/tools/clippy/tests/ui/unicode.rs
+++ b/src/tools/clippy/tests/ui/unicode.rs
@@ -1,7 +1,11 @@
-#[warn(clippy::zero_width_space)]
+#[warn(clippy::invisible_characters)]
 fn zero() {
     print!("Here >​< is a ZWS, and ​another");
     print!("This\u{200B}is\u{200B}fine");
+    print!("Here >­< is a SHY, and ­another");
+    print!("This\u{ad}is\u{ad}fine");
+    print!("Here >⁠< is a WJ, and ⁠another");
+    print!("This\u{2060}is\u{2060}fine");
 }
 
 #[warn(clippy::unicode_not_nfc)]
diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr
index 4575a13..3fca463 100644
--- a/src/tools/clippy/tests/ui/unicode.stderr
+++ b/src/tools/clippy/tests/ui/unicode.stderr
@@ -1,13 +1,25 @@
-error: zero-width space detected
+error: invisible character detected
   --> $DIR/unicode.rs:3:12
    |
 LL |     print!("Here >​< is a ZWS, and ​another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"`
    |
-   = note: `-D clippy::zero-width-space` implied by `-D warnings`
+   = note: `-D clippy::invisible-characters` implied by `-D warnings`
+
+error: invisible character detected
+  --> $DIR/unicode.rs:5:12
+   |
+LL |     print!("Here >­< is a SHY, and ­another");
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"`
+
+error: invisible character detected
+  --> $DIR/unicode.rs:7:12
+   |
+LL |     print!("Here >⁠< is a WJ, and ⁠another");
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"`
 
 error: non-NFC Unicode sequence detected
-  --> $DIR/unicode.rs:9:12
+  --> $DIR/unicode.rs:13:12
    |
 LL |     print!("̀àh?");
    |            ^^^^^ help: consider replacing the string with: `"̀àh?"`
@@ -15,12 +27,12 @@
    = note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:15:12
+  --> $DIR/unicode.rs:19:12
    |
 LL |     print!("Üben!");
    |            ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
    |
    = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
index ad0d038..b45b27d 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
@@ -13,12 +13,12 @@
     // Forward examples
     vec.sort();
     vec.sort_unstable();
-    vec.sort_by_key(|&a| (a + 5).abs());
-    vec.sort_unstable_by_key(|&a| id(-a));
+    vec.sort_by_key(|a| (a + 5).abs());
+    vec.sort_unstable_by_key(|a| id(-a));
     // Reverse examples
-    vec.sort_by_key(|&b| Reverse(b));
-    vec.sort_by_key(|&b| Reverse((b + 5).abs()));
-    vec.sort_unstable_by_key(|&b| Reverse(id(-b)));
+    vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow
+    vec.sort_by_key(|b| Reverse((b + 5).abs()));
+    vec.sort_unstable_by_key(|b| Reverse(id(-b)));
     // Negative examples (shouldn't be changed)
     let c = &7;
     vec.sort_by(|a, b| (b - a).cmp(&(a - b)));
@@ -26,10 +26,11 @@
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
 
-    // Ignore vectors of references
+    // Vectors of references are fine as long as the resulting key does not borrow
     let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
-    vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
-    vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_by_key(|a| (***a).abs());
+    vec.sort_unstable_by_key(|a| (***a).abs());
+    // `Reverse(b)` would borrow in the following cases, don't lint
     vec.sort_by(|a, b| b.cmp(a));
     vec.sort_unstable_by(|a, b| b.cmp(a));
 }
@@ -68,10 +69,9 @@
     }
 }
 
-// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
-// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
-// not linted.
+// The closure parameter is not dereferenced anymore, so non-Copy types can be linted
 mod issue_6001 {
+    use super::*;
     struct Test(String);
 
     impl Test {
@@ -85,11 +85,11 @@
         let mut args: Vec<Test> = vec![];
 
         // Forward
-        args.sort_by(|a, b| a.name().cmp(&b.name()));
-        args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+        args.sort_by_key(|a| a.name());
+        args.sort_unstable_by_key(|a| a.name());
         // Reverse
-        args.sort_by(|a, b| b.name().cmp(&a.name()));
-        args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+        args.sort_by_key(|b| Reverse(b.name()));
+        args.sort_unstable_by_key(|b| Reverse(b.name()));
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
index 9746f6e..be2abe7 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
@@ -16,7 +16,7 @@
     vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
     vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
     // Reverse examples
-    vec.sort_by(|a, b| b.cmp(a));
+    vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow
     vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
     vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
     // Negative examples (shouldn't be changed)
@@ -26,10 +26,11 @@
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
 
-    // Ignore vectors of references
+    // Vectors of references are fine as long as the resulting key does not borrow
     let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
     vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
     vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    // `Reverse(b)` would borrow in the following cases, don't lint
     vec.sort_by(|a, b| b.cmp(a));
     vec.sort_unstable_by(|a, b| b.cmp(a));
 }
@@ -68,10 +69,9 @@
     }
 }
 
-// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
-// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
-// not linted.
+// The closure parameter is not dereferenced anymore, so non-Copy types can be linted
 mod issue_6001 {
+    use super::*;
     struct Test(String);
 
     impl Test {
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
index 70c6cf0..5060793 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
@@ -16,31 +16,61 @@
   --> $DIR/unnecessary_sort_by.rs:16:5
    |
 LL |     vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())`
 
 error: use Vec::sort_by_key here instead
   --> $DIR/unnecessary_sort_by.rs:17:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&a| id(-a))`
-
-error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:19:5
-   |
-LL |     vec.sort_by(|a, b| b.cmp(a));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))`
 
 error: use Vec::sort_by_key here instead
   --> $DIR/unnecessary_sort_by.rs:20:5
    |
 LL |     vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| Reverse((b + 5).abs()))`
 
 error: use Vec::sort_by_key here instead
   --> $DIR/unnecessary_sort_by.rs:21:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&b| Reverse(id(-b)))`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| Reverse(id(-b)))`
 
-error: aborting due to 7 previous errors
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:31:5
+   |
+LL |     vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:32:5
+   |
+LL |     vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:88:9
+   |
+LL |         args.sort_by(|a, b| a.name().cmp(&b.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:89:9
+   |
+LL |         args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:91:9
+   |
+LL |         args.sort_by(|a, b| b.name().cmp(&a.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| Reverse(b.name()))`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:92:9
+   |
+LL |         args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| Reverse(b.name()))`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 17649df..59f64e7 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -208,10 +208,13 @@
                 config.parse_name_value_directive(line, "needs-llvm-components")
             {
                 let components: HashSet<_> = config.llvm_components.split_whitespace().collect();
-                if !needed_components
+                if let Some(missing_component) = needed_components
                     .split_whitespace()
-                    .all(|needed_component| components.contains(needed_component))
+                    .find(|needed_component| !components.contains(needed_component))
                 {
+                    if env::var_os("COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS").is_some() {
+                        panic!("missing LLVM component: {}", missing_component);
+                    }
                     return true;
                 }
             }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index acad316..d85558e 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3199,8 +3199,18 @@
                     from_file = format!("{}.{}.mir", test_name, first_pass);
                     to_file = Some(second_file);
                 } else {
-                    expected_file =
-                        format!("{}{}.mir", test_name.trim_end_matches(".mir"), bit_width);
+                    let ext_re = Regex::new(r#"(\.(mir|dot|html))$"#).unwrap();
+                    let cap = ext_re
+                        .captures_iter(test_name)
+                        .next()
+                        .expect("test_name has an invalid extension");
+                    let extension = cap.get(1).unwrap().as_str();
+                    expected_file = format!(
+                        "{}{}{}",
+                        test_name.trim_end_matches(extension),
+                        bit_width,
+                        extension,
+                    );
                     from_file = test_name.to_string();
                     assert!(
                         test_names.next().is_none(),
diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml
index 0994cd2..e5d870c 100644
--- a/src/tools/linkchecker/Cargo.toml
+++ b/src/tools/linkchecker/Cargo.toml
@@ -7,3 +7,7 @@
 [[bin]]
 name = "linkchecker"
 path = "main.rs"
+
+[dependencies]
+regex = "1"
+once_cell = "1"
diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh
index bbccc17..b68053c 100755
--- a/src/tools/linkchecker/linkcheck.sh
+++ b/src/tools/linkchecker/linkcheck.sh
@@ -34,6 +34,9 @@
     exit 1
 fi
 
+# Avoid failure caused by newer mdbook.
+export MDBOOK_OUTPUT__HTML__INPUT_404=""
+
 book_name=""
 # Iterative will avoid cleaning up, so you can quickly run it repeatedly.
 iterative=0
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 4fe493a..f213944 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -21,6 +21,9 @@
 use std::path::{Component, Path, PathBuf};
 use std::rc::Rc;
 
+use once_cell::sync::Lazy;
+use regex::Regex;
+
 use crate::Redirect::*;
 
 // Add linkcheck exceptions here
@@ -50,6 +53,44 @@
     ("alloc/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]),
 ];
 
+#[rustfmt::skip]
+const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[
+    // This will never have links that are not in other pages.
+    // To avoid repeating the exceptions twice, an empty list means all broken links are allowed.
+    ("reference/print.html", &[]),
+    // All the reference 'links' are actually ENBF highlighted as code
+    ("reference/comments.html", &[
+         "/</code> <code>!",
+         "*</code> <code>!",
+    ]),
+    ("reference/identifiers.html", &[
+         "a</code>-<code>z</code> <code>A</code>-<code>Z",
+         "a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_",
+         "a</code>-<code>z</code> <code>A</code>-<code>Z</code>] [<code>a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_",
+    ]),
+    ("reference/tokens.html", &[
+         "0</code>-<code>1",
+         "0</code>-<code>7",
+         "0</code>-<code>9",
+         "0</code>-<code>9",
+         "0</code>-<code>9</code> <code>a</code>-<code>f</code> <code>A</code>-<code>F",
+    ]),
+    ("reference/notation.html", &[
+         "b</code> <code>B",
+         "a</code>-<code>z",
+    ]),
+    // This is being used in the sense of 'inclusive range', not a markdown link
+    ("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
+    ("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
+    ("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
+    ("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
+    ("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
+
+];
+
+static BROKEN_INTRA_DOC_LINK: Lazy<Regex> =
+    Lazy::new(|| Regex::new(r#"\[<code>(.*)</code>\]"#).unwrap());
+
 macro_rules! t {
     ($e:expr) => {
         match $e {
@@ -138,6 +179,14 @@
     }
 }
 
+fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
+    if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+        entry.1.is_empty() || entry.1.contains(&link)
+    } else {
+        false
+    }
+}
+
 fn is_exception(file: &Path, link: &str) -> bool {
     if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
         entry.1.contains(&link)
@@ -292,6 +341,19 @@
             }
         }
     });
+
+    // Search for intra-doc links that rustdoc didn't warn about
+    // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
+    // NOTE: only looks at one line at a time; in practice this should find most links
+    for (i, line) in contents.lines().enumerate() {
+        for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
+            if !is_intra_doc_exception(file, &broken_link[1]) {
+                *errors = true;
+                print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1);
+                println!("{}", &broken_link[0]);
+            }
+        }
+    }
     Some(pretty_file)
 }
 
diff --git a/src/tools/miri b/src/tools/miri
index 2f84bfc..1b3a27c 160000
--- a/src/tools/miri
+++ b/src/tools/miri
@@ -1 +1 @@
-Subproject commit 2f84bfc57dd0ef22269bb84dae10f71e5e23e85d
+Subproject commit 1b3a27c4298ebed55851657934483366a02abc3b
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 9cfde0c..7586f5a 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -33,7 +33,7 @@
     'rust-by-example': {'steveklabnik', 'marioidival'},
     'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'},
     'edition-guide': {'ehuss', 'steveklabnik'},
-    'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'},
+    'rustc-dev-guide': {'spastorino', 'amanjeev', 'JohnTitor'},
 }
 
 LABELS = {
@@ -157,9 +157,6 @@
 
         cc @{}, do you think you would have time to do the follow-up work?
         If so, that would be great!
-
-        And nominating for compiler team prioritization.
-
         ''').format(
             relevant_pr_number, tool, status_description,
             REPOS.get(tool), relevant_pr_user
diff --git a/src/tools/rls b/src/tools/rls
index db6a9e0..1f686d5 160000
--- a/src/tools/rls
+++ b/src/tools/rls
@@ -1 +1 @@
-Subproject commit db6a9e01aa3453b64c05707e99e97045f9712957
+Subproject commit 1f686d5f707269b1086f6afcdced36225c0c5ff7
diff --git a/src/tools/rust-demangler/Cargo.toml b/src/tools/rust-demangler/Cargo.toml
index 0b8d974..ac684a3 100644
--- a/src/tools/rust-demangler/Cargo.toml
+++ b/src/tools/rust-demangler/Cargo.toml
@@ -1,11 +1,12 @@
 [package]
 authors = ["The Rust Project Developers"]
 name = "rust-demangler"
-version = "0.0.0"
+version = "0.0.1"
 edition = "2018"
 
 [dependencies]
-rustc-demangle = "0.1"
+regex = "1.0"
+rustc-demangle = "0.1.17"
 
 [[bin]]
 name = "rust-demangler"
diff --git a/src/tools/rust-demangler/main.rs b/src/tools/rust-demangler/main.rs
index a9f1011..fd031cc 100644
--- a/src/tools/rust-demangler/main.rs
+++ b/src/tools/rust-demangler/main.rs
@@ -21,19 +21,110 @@
 //! $ "${TARGET}"/llvm/bin/llvm-cov show --Xdemangler="${TARGET}"/stage0-tools-bin/rust-demangler \
 //!   --instr-profile=main.profdata ./main --show-line-counts-or-regions
 //! ```
+//!
+//! Note regarding crate disambiguators:
+//!
+//! Some demangled symbol paths can include "crate disambiguator" suffixes, represented as a large
+//! hexadecimal value enclosed in square braces, and appended to the name of the crate. a suffix to the
+//! original crate name. For example, the `core` crate, here, includes a disambiguator:
+//!
+//! ```rust
+//!     <generics::Firework<f64> as core[a7a74cee373f048]::ops::drop::Drop>::drop
+//! ```
+//!
+//! These disambiguators are known to vary depending on environmental circumstances. As a result,
+//! tests that compare results including demangled names can fail across development environments,
+//! particularly with cross-platform testing. Also, the resulting crate paths are not syntactically
+//! valid, and don't match the original source symbol paths, which can impact development tools.
+//!
+//! For these reasons, by default, `rust-demangler` uses a heuristic to remove crate disambiguators
+//! from their original demangled representation before printing them to standard output. If crate
+//! disambiguators are required, add the `-d` (or `--disambiguators`) flag, and the disambiguators
+//! will not be removed.
+//!
+//! Also note that the disambiguators are stripped by a Regex pattern that is tolerant to some
+//! variation in the number of hexadecimal digits. The disambiguators come from a hash value, which
+//! typically generates a 16-digit hex representation on a 64-bit architecture; however, leading
+//! zeros are not included, which can shorten the hex digit length, and a different hash algorithm
+//! that might also be dependent on the architecture, might shorten the length even further. A
+//! minimum length of 5 digits is assumed, which should be more than sufficient to support hex
+//! representations that generate only 8-digits of precision with an extremely rare (but not
+//! impossible) result with up to 3 leading zeros.
+//!
+//! Using a minimum number of digits less than 5 risks the possibility of stripping demangled name
+//! components with a similar pattern. For example, some closures instantiated multiple times
+//! include their own disambiguators, demangled as non-hashed zero-based indexes in square brackets.
+//! These disambiguators seem to have more analytical value (for instance, in coverage analysis), so
+//! they are not removed.
 
+use regex::Regex;
 use rustc_demangle::demangle;
 use std::io::{self, Read, Write};
 
+const REPLACE_COLONS: &str = "::";
+
 fn main() -> io::Result<()> {
+    // FIXME(richkadel): In Issue #77615 discussed updating the `rustc-demangle` library, to provide
+    // an option to generate demangled names without including crate disambiguators. If that
+    // happens, update this tool to use that option (if the `-d` flag is not set) instead stripping
+    // them via the Regex heuristic. The update the doc comments and help.
+
+    // Strip hashed hexadecimal crate disambiguators. Leading zeros are not enforced, and can be
+    // different across different platform/architecture types, so while 16 hex digits are common,
+    // they can also be shorter.
+    //
+    // Also note that a demangled symbol path may include the `[<digits>]` pattern, with zero-based
+    // indexes (such as for closures, and possibly for types defined in anonymous scopes). Preferably
+    // these should not be stripped.
+    //
+    // The minimum length of 5 digits supports the possibility that some target architecture (maybe
+    // a 32-bit or smaller architecture) could generate a hash value with a maximum of 8 digits,
+    // and more than three leading zeros should be extremely unlikely. Conversely, it should be
+    // sufficient to assume the zero-based indexes for closures and anonymous scopes will never
+    // exceed the value 9999.
+    let mut strip_crate_disambiguators = Some(Regex::new(r"\[[a-f0-9]{5,16}\]::").unwrap());
+
+    let mut args = std::env::args();
+    let progname = args.next().unwrap();
+    for arg in args {
+        if arg == "--disambiguators" || arg == "-d" {
+            strip_crate_disambiguators = None;
+        } else {
+            eprintln!();
+            eprintln!("Usage: {} [-d|--disambiguators]", progname);
+            eprintln!();
+            eprintln!(
+                "This tool converts a list of Rust mangled symbols (one per line) into a\n\
+                corresponding list of demangled symbols."
+            );
+            eprintln!();
+            eprintln!(
+                "With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\
+                include crate disambiguators (a hexadecimal hash value, typically up to 16 digits\n\
+                long, enclosed in square brackets)."
+            );
+            eprintln!();
+            eprintln!(
+                "By default, crate disambiguators are removed, using a heuristics-based regular\n\
+                expression. (See the `rust-demangler` doc comments for more information.)"
+            );
+            eprintln!();
+            std::process::exit(1)
+        }
+    }
+
     let mut buffer = String::new();
     io::stdin().read_to_string(&mut buffer)?;
     let lines = buffer.lines();
-    let mut demangled = Vec::new();
+    let mut demangled_lines = Vec::new();
     for mangled in lines {
-        demangled.push(demangle(mangled).to_string());
+        let mut demangled = demangle(mangled).to_string();
+        if let Some(re) = &strip_crate_disambiguators {
+            demangled = re.replace_all(&demangled, REPLACE_COLONS).to_string();
+        }
+        demangled_lines.push(demangled);
     }
-    demangled.push("".to_string());
-    io::stdout().write_all(demangled.join("\n").as_bytes())?;
+    demangled_lines.push("".to_string());
+    io::stdout().write_all(demangled_lines.join("\n").as_bytes())?;
     Ok(())
 }
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
index 01f2ead..97d0301 160000
--- a/src/tools/rustfmt
+++ b/src/tools/rustfmt
@@ -1 +1 @@
-Subproject commit 01f2eadccc74cf70eb11e6300ffa7e02b18b0027
+Subproject commit 97d0301011533e1c131c0edd660d77b4bd476c8b
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 589be26..62cfa85 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -9,19 +9,56 @@
 
 // All files are executable on Windows, so just check on Unix.
 #[cfg(windows)]
-pub fn check(_path: &Path, _bad: &mut bool) {}
+pub fn check(_path: &Path, _output: &Path, _bad: &mut bool) {}
 
 #[cfg(unix)]
-pub fn check(path: &Path, bad: &mut bool) {
+pub fn check(path: &Path, output: &Path, bad: &mut bool) {
     use std::fs;
     use std::os::unix::prelude::*;
     use std::process::{Command, Stdio};
 
-    if let Ok(contents) = fs::read_to_string("/proc/version") {
-        // Probably on Windows Linux Subsystem or Docker via VirtualBox,
-        // all files will be marked as executable, so skip checking.
-        if contents.contains("Microsoft") || contents.contains("boot2docker") {
-            return;
+    fn is_executable(path: &Path) -> std::io::Result<bool> {
+        Ok(path.metadata()?.mode() & 0o111 != 0)
+    }
+
+    // We want to avoid false positives on filesystems that do not support the
+    // executable bit. This occurs on some versions of Window's linux subsystem,
+    // for example.
+    //
+    // We try to create the temporary file first in the src directory, which is
+    // the preferred location as it's most likely to be on the same filesystem,
+    // and then in the output (`build`) directory if that fails. Sometimes we
+    // see the source directory mounted as read-only which means we can't
+    // readily create a file there to test.
+    //
+    // See #36706 and #74753 for context.
+    let mut temp_path = path.join("tidy-test-file");
+    match fs::File::create(&temp_path).or_else(|_| {
+        temp_path = output.join("tidy-test-file");
+        fs::File::create(&temp_path)
+    }) {
+        Ok(file) => {
+            let exec = is_executable(&temp_path).unwrap_or(false);
+            std::mem::drop(file);
+            std::fs::remove_file(&temp_path).expect("Deleted temp file");
+            if exec {
+                // If the file is executable, then we assume that this
+                // filesystem does not track executability, so skip this check.
+                return;
+            }
+        }
+        Err(e) => {
+            // If the directory is read-only or we otherwise don't have rights,
+            // just don't run this check.
+            //
+            // 30 is the "Read-only filesystem" code at least in one CI
+            //    environment.
+            if e.raw_os_error() == Some(30) {
+                eprintln!("tidy: Skipping binary file check, read-only filesystem");
+                return;
+            }
+
+            panic!("unable to create temporary file `{:?}`: {:?}", temp_path, e);
         }
     }
 
@@ -36,8 +73,7 @@
                 return;
             }
 
-            let metadata = t!(entry.metadata(), file);
-            if metadata.mode() & 0o111 != 0 {
+            if t!(is_executable(&file), file) {
                 let rel_path = file.strip_prefix(path).unwrap();
                 let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
                 let output = Command::new("git")
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 3567053..0c52fee 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -116,7 +116,6 @@
     "libz-sys",
     "lock_api",
     "log",
-    "log_settings",
     "maybe-uninit",
     "md-5",
     "measureme",
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 36c9e58e..e1525f8 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -13,6 +13,8 @@
 fn main() {
     let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into();
     let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into();
+    let output_directory: PathBuf =
+        env::args_os().nth(3).expect("need path to output directory").into();
 
     let src_path = root_path.join("src");
     let library_path = root_path.join("library");
@@ -36,9 +38,9 @@
     unit_tests::check(&library_path, &mut bad);
 
     // Checks that need to be done for both the compiler and std libraries.
-    bins::check(&src_path, &mut bad);
-    bins::check(&compiler_path, &mut bad);
-    bins::check(&library_path, &mut bad);
+    bins::check(&src_path, &output_directory, &mut bad);
+    bins::check(&compiler_path, &output_directory, &mut bad);
+    bins::check(&library_path, &output_directory, &mut bad);
 
     style::check(&src_path, &mut bad);
     style::check(&compiler_path, &mut bad);
diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs
index b8d60a5..6a492bb 100644
--- a/src/tools/tier-check/src/main.rs
+++ b/src/tools/tier-check/src/main.rs
@@ -25,8 +25,6 @@
     let doc_targets: HashSet<_> = doc_targets_md
         .lines()
         .filter(|line| line.starts_with('`') && line.contains('|'))
-        // These platforms only exist on macos.
-        .filter(|line| !line.contains("[^apple]") || cfg!(target_os = "macos"))
         .map(|line| line.split('`').skip(1).next().expect("expected target code span"))
         .collect();
 
diff --git a/src/version b/src/version
index 9db5ea1..7f3a46a 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.48.0
+1.49.0
diff --git a/triagebot.toml b/triagebot.toml
index bcdc400..fc733b9 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -3,6 +3,7 @@
     "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
     "D-*",
     "requires-nightly",
+    "regression-*",
     # I-* without I-nominated
     "I-*", "!I-nominated",
     "AsyncAwait-OnDeck",
@@ -74,6 +75,7 @@
 
 [autolabel."I-prioritize"]
 trigger_labels = [
+    "regression-untriaged",
     "regression-from-stable-to-stable",
     "regression-from-stable-to-beta",
     "regression-from-stable-to-nightly",